[Erforderliches Thema DI] Implementieren und verstehen Sie den Mechanismus von DI mit Go

Einführung

Verschiedene Konzepte wie saubere Architektur und Zwiebelarchitektur wurden vorgeschlagen, Ich war frustriert, nachdem ich es studiert hatte. Weil ich überhaupt nicht viel über DI und Abhängigkeit wusste. Ja, ich habe in der falschen Reihenfolge gelernt. Ich bin froh, dass ich es bemerkt habe.

Deshalb habe ich versucht, DI so leicht wie möglich auf leicht verständliche Weise zusammenzufassen. Nachdem Sie diesen Artikel gelesen haben, werden Sie definitiv die Vorteile von ** DI ** verstehen und implementieren können

Was ist DI?

DI ist eine Abkürzung für Dependency Injection

Um das DI-Entwurfsmuster kurz zu erklären, Definieren Sie das Objekt als Schnittstelle, und der Benutzer sollte die Schnittstelle anstelle des Implementierungsobjekts verwenden. Implementierungsobjekte können ersetzt werden, indem sie von außen in die Schnittstelle eingefügt werden.

Was ist ein DI-Container?

DI-Container ist ein ** Framework ** zur Realisierung von DI

Definition von Wörtern

Während ich lernte, gab es einige Wörter, die ich nicht verstand und ich war sehr verwirrt. Lassen Sie uns also zuerst die Definition von Wörtern abgleichen.

・ Wo ist es von außen? Von anderen Objekten!

・ Was ist Abhängigkeit? Ein B-Objekt, für das ein A-Objekt erforderlich ist Mit anderen Worten, das A-Objekt kennt den Inhalt des B-Objekts. Im Moment denken Sie vielleicht, dass Sie von Neu abhängig sind

・ Du sagst, du bist nicht davon abhängig, aber du bist davon abhängig, oder? Sie verwenden ein A-Objekt mit einem B-Objekt, das in die A-Schnittstelle eingefügt wurde! !! Ist das abhängig? Richtig? Ich habe immer gedacht. Das war das nervigste. Um genau zu sein, hängt das B-Objekt von der A-Schnittstelle ab. Das B-Objekt hängt also nicht vom A-Objekt ab. (Manchmal kommt es auf die Abstraktion an) Das Gute daran ist, dass B-Objekte implementiert werden können, ohne A-Objekte zu kennen. Details werden später beschrieben.

Mit DI glücklich sein

** "Warum benutzt du DI?" Dies ist das Wichtigste. ** **. Ich glaube nicht, dass es verwendet werden kann, selbst wenn ich DI verwende, ohne dies zu wissen. Es ist wichtig, sich immer des ** Zwecks der Verwendung der Methode "wofür" bewusst zu sein. Dann werde ich schreiben, dass Sie mit DI glücklich sein können.

** ・ Da es nicht von einer externen Datenbank abhängt, ist es resistent gegen Änderungen. ** **. Grund: Weil das Implementierungsobjekt über die Schnittstelle injiziert wird Die Logikseite, die die Schnittstelle verwendet, kann sie verwenden, ohne das Implementierungsobjekt zu kennen.

** ・ Einfacher Komponententest ** Grund: Wie oben, jedoch durch Verspotten der Datenbank (wie eine gefälschte Datenbank) Sie können testen, ohne die Logik auf der Seite zu ändern, die die Schnittstelle verwendet. Beide Ergebnisse sind problematisch, auch wenn Sie wechseln, weil Sie das Äußere nicht kennen (unabhängig).

** ・ Einfach einfacher zu codieren. ** **. Grund: Angenommen, Sie haben die Klassen A und B. A braucht B (Abhängigkeit). In diesem Fall kann A nicht ohne B implementiert werden. Wenn A jedoch die Schnittstelle von B implementiert, kann es ohne B implementiert werden. Das Injizieren eines B-Objekts über eine Schnittstelle entspricht A mit B.

Schauen Sie sich den Code an und erkennen Sie den Unterschied

Bisher haben wir das Konzept und den Mechanismus von DI erklärt. Von hier aus werden wir uns den tatsächlichen Code ansehen und ihn verstehen. Auch wenn Sie es zuerst nicht verstehen, sollten Sie es verstehen können, wenn Sie es oft lesen! Eigentlich war ich.

Der zu erstellende Code besteht aus den folgenden drei. ・ Repository-Schicht ・ ・ ・ Schicht für die Verbindung zur Datenbank ・ Serviceschicht ・ ・ ・ Schicht, die das Repository aufruft ・ Anrufschicht ・ ・ ・ Schicht, die das Ganze bedient

Abhängiger Code

Schauen wir uns zunächst den unordentlichen Code an, der Abhängigkeiten aufweist. (* Ich glaube, ich habe diesen Code geschrieben, als ich mit dem Programmieren angefangen habe.)

Repository-Schicht Die erstellte Datenbank wird direkt an das Benutzer-Repository übergeben. (Schlecht: Die Repository-Schicht hängt von der Datenbank ab. Ich kenne MySQL.)

package repository

type UserRepository struct {
	db sql.DB
}

func NewUserRepository() *UserRepository {
	//DB-Erstellung
	db, _ := sql.Open("mysql", "root:@/database")
	//DB direkt im Repository erstellt
	return &UserRepository{*db}
}

Serviceschicht Das Repository ist neu und wird direkt an den Dienst übergeben. (Schlechter Punkt: Die Serviceschicht hängt vom Repository ab.)

package service

type UserService struct {
	ur repository.UserRepository
}

func NewUserService() *UserService {
	//Repository erstellen
	ur := repository.NewUserRepository()
	//Repository direkt für den Service erstellt
	return &UserService{*ur}
}


Anrufschicht Wenn der Dienst neu ist, werden ein festes Repository und eine Datenbank erstellt.

package main

func main() {

	us := service.NewUserService()
	//Gonyo Gonyo benutzt uns
}

Ich habe einmal schlechten Code gesehen. Sie können sehen, dass es sehr davon abhängt. Für alle Fälle erneut bestätigt, ist eine Abhängigkeit ein Zustand, in dem ein Objekt den Inhalt eines Objekts kennt.

Code, der DI einführte

Von hier aus sehen wir uns einen sehr schönen Code an, der DI einführt. (* Wenn ich den Code zum ersten Mal sehe, der DI verwendet, sieht er sehr schmutzig aus ...)

Ich habe eine wichtige Sache vergessen, bevor ich mir den Code angesehen habe. Es gibt vier Möglichkeiten, DI zu erreichen. 1.Constructor Injection 2.Setter Injection 3.Interface Injection 4.Field Injection

Dieses Mal werde ich 1 Konstruktorinjektion verwenden. Ich denke, das ist das Beste für mich.

Repository-Schicht In NewUserRepository wird db als Konstruktor verwendet. Daher hängt es nicht von db ab. Außerdem gibt return die Schnittstelle zurück. Dadurch wird auch die Abhängigkeit zwischen der Repository-Schicht und der Service-Schicht beseitigt.

package repository

type UserRepository interface {
	CreateUser(ctx context.Context, user *model.User)
}

type userRepository struct {
	db sql.DB
}

func NewUserRepository(db *sql.DB) UserRepository {
	return &userRepository{*db}
}

func (ur *userRepository) CreateUser(ctx context.Context, user *model.User) {
	ur.db.Query("INSERT INTO Tabellenname (Spaltenname 1),Spaltenname 2,……)")
}

Serviceschicht NewUserService verwendet in seinem Konstruktor eine Repository-Schnittstelle. Daher hängt es nicht vom Repository ab. Außerdem gibt return die Schnittstelle zurück. Dadurch wird auch die Abhängigkeit zwischen der Serviceschicht und der Benutzerebene beseitigt.

package service

type UserService interface {
	CreateUser(ctx context.Context, user *model.User)
}

type userService struct {
	ur repository.UserRepository
}

func NewUserService(ur repository.UserRepository) UserService {
	return &userService{ur}
}

func (us *userService) CreateUser(ctx context.Context, user *model.User) {
	us.ur.CreateUser(ctx, user)
}

Ebene auf der Benutzerseite ur := repository.NewUserRepository(db) Jede Datenbank kann akzeptiert werden, solange es sich um eine Datenbank handelt.

us := service.NewUserService(ur) Solange ur (Repository) ein Repository ist, kann jedes Repository akzeptiert werden.

Dies macht es einfach, es zum Zeitpunkt des Tests durch ein anderes Repository oder eine andere Datenbank zu ersetzen. Da sie sich nicht kennen, gibt es keine Abhängigkeiten und Änderungen können leicht vorgenommen werden.

(* Zur Vereinfachung der Erklärung wird die Erstellung von db in main geschrieben.)

package main

func main() {
	db, err := sql.Open("mysql", "root:@/database")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	ur := repository.NewUserRepository(db)
	us := service.NewUserService(ur)

	//Gonyo Gonyo benutzt uns
}

Zusammenfassung

Ich habe über DI erklärt. Indem Sie es tatsächlich implementieren oder in einem Artikel wie diesem zusammenstellen, Das Innere meines Kopfes war sehr erfrischend. Auch wenn ich denke, dass ich es verstehe, habe ich das Gefühl, dass es möglicherweise nicht möglich ist, wenn es unerwartet implementiert wird. Wenn Sie DI studieren, versuchen Sie bitte, es selbst zu implementieren.

Verweise

https://recruit-tech.co.jp/blog/2017/12/11/go_dependency_injection/ https://github.com/akito0107/dicon http://inukirom.hatenablog.com/entry/di-in-go

Recommended Posts

[Erforderliches Thema DI] Implementieren und verstehen Sie den Mechanismus von DI mit Go
Spielen Sie mit dem Passwortmechanismus von GitHub Webhook und Python
Implementieren und verstehen Sie den Union-Find-Baum in Go
[Statistik] Verstehen Sie den Mechanismus von Q-Q-Plots mit Animation.
Visualisieren Sie den Bereich der internen und externen Einfügungen mit Python
[Ev3dev] Lassen Sie uns den Mechanismus der LCD-Steuerung (Bildschirmsteuerung) verstehen
Implementieren Sie mit OpenModelica das mathematische Modell "SIR-Modell" von Infektionskrankheiten (Beispiel für wiederholte Regulierung und Entspannung)
Implementieren Sie mit Open Modelica das mathematische Modell "SIR-Modell" von Infektionskrankheiten
Sehen Sie, wie schnell Sie mit NumPy / SciPy beschleunigen können
"Tiefe Kopie" und "flache Kopie", um mit dem kleinsten Beispiel zu verstehen
Mechanismus von Pyenv und Virtualenv
Ich habe die Geschwindigkeit von Hash mit Topaz, Ruby und Python verglichen
[Statistik] Visualisieren und verstehen Sie die Hamiltonsche Monte-Carlo-Methode mit Animation.
Verbesserung der Wiederverwendbarkeit und Wartbarkeit von mit Luigi erstellten Workflows
Der Versuch, Segmentbäume Schritt für Schritt zu implementieren und zu verstehen (Python)
Ich habe versucht, mit Go einen exklusiven Kontrollmechanismus zu erstellen
Ich habe den Mechanismus der Flaschenanmeldung untersucht!
Verstehen Sie den Inhalt der sklearn-Pipeline
Über den Grundtyp von Go
Koexistenz von Python2 und 3 mit CircleCI (1.0)
Ich habe die numerische Berechnung von Python durch Rust ersetzt und die Geschwindigkeit verglichen
Berechnen Sie die kürzeste Route eines Diagramms mit der Dyxtra-Methode und Python
Sie können auch die Kommunikation von DB und Cache mit Curl überprüfen
Stellen Sie die Behälterbreite mit dem Histogramm von Matplotlib und Seaborn klar und ordentlich ein
Die goldene Kombination aus Embulk und BigQuery glänzt mit Digdag noch mehr
Ich habe den Akkord des Songs mit word2vec vektorisiert und mit t-SNE visualisiert
Finden Sie die allgemeinen Begriffe der Tribonacci-Sequenz in linearer Algebra und Python
Lesen Sie das Diagrammbild mit OpenCV und ermitteln Sie die Koordinaten des Endpunkts des Diagramms
Die Geschichte einer Soundkamera mit Touch Designer und ReSpeaker
Holen Sie sich Artikelbesuche und Likes mit Qiita API + Python
Erstellen Sie DNN-CRF mit Chainer und erkennen Sie den Akkordfortschritt der Musik
Erhalten und schätzen Sie die Form des Kopfes mit Dlib und OpenCV mit Python
Implementieren Sie ein Modell mit Status und Verhalten (3) - Beispiel für die Implementierung durch den Dekorateur
Ich habe die Geschwindigkeit der Listeneinschlussnotation für und während mit Python2.7 gemessen.
Versuchen Sie, den Hintergrund und das sich bewegende Objekt des Videos mit OpenCV zu trennen
Artikel, der eine Person sein kann, die den Mechanismus der API versteht und beherrscht (mit Python-Code)