[Objet obligatoire DI] Implémenter et comprendre le mécanisme de DI avec Go

introduction

Différents concepts tels que l'architecture propre et l'architecture oignon ont été proposés, J'étais frustré après l'avoir étudié. Parce que je ne savais pas grand-chose sur l'ID et la dépendance en premier lieu. Oui, j'étudiais dans le mauvais ordre. Eh bien, je suis content de l'avoir remarqué.

Par conséquent, j'ai essayé de résumer la DI avec autant de détails que possible d'une manière facile à comprendre. Après avoir lu cet article, vous serez certainement en mesure de comprendre et de mettre en œuvre les avantages de ** DI **

Qu'est-ce que DI?

DI est une abréviation pour Dependency Injection

Pour expliquer brièvement le modèle de conception DI, Définissez l'objet en tant qu'interface et l'utilisateur doit utiliser l'interface au lieu de l'objet d'implémentation. Les objets d'implémentation peuvent être remplacés en les injectant dans l'interface depuis l'extérieur.

Qu'est-ce qu'un conteneur DI?

Le conteneur DI est un ** framework ** pour aider à réaliser DI

Définition des mots

Pendant que j'apprenais, il y avait des mots que je ne comprenais pas et j'étais très confus. Alors faisons correspondre la définition des mots en premier.

・ D'où vient-il de l'extérieur? À partir d'autres objets!

・ Qu'est-ce que la dépendance? Un objet B qui nécessite un objet A En d'autres termes, l'objet A connaît le contenu de l'objet B. Pour le moment, vous pensez peut-être que vous dépendez de New

・ Vous dites que vous n'en dépendez pas, mais vous en dépendez, non? Vous utilisez un objet A avec un objet B injecté dans l'interface A! !! Cela dépend-il? Droite? J'ai toujours pensé. C'était la chose la plus ennuyeuse. Pour être précis, l'objet B dépend de l'interface A. Ainsi, l'objet B ne dépend pas de l'objet A. (Parfois cela dépend de l'abstraction) Ce qui est bien à ce sujet, c'est que les objets B peuvent être implémentés sans connaître les objets A. Les détails seront décrits plus tard.

Être heureux en utilisant DI

** "Pourquoi utilisez-vous DI?" C'est le plus important. ** ** Je ne pense pas qu'il puisse être utilisé même si j'utilise DI sans le savoir. Il est important de toujours être conscient du ** but de l'utilisation de la méthode "pour quoi". Ensuite, j'écrirai que vous pouvez être heureux en utilisant DI.

** ・ Parce qu'il ne dépend pas d'une base de données externe, il résiste aux changements. ** ** Raison: car il injecte l'objet d'implémentation via l'interface Le côté logique qui utilise l'interface peut l'utiliser sans connaître l'objet d'implémentation.

** ・ Test unitaire facile ** Raison: comme ci-dessus, mais en se moquant de la DB (comme une fausse DB) Vous pouvez tester sans changer la logique du côté qui utilise l'interface. Les deux résultats sont problématiques même si vous changez parce que vous ne connaissez pas l'extérieur (indépendant).

** ・ Simplement plus facile à coder. ** ** Raison: supposons que vous ayez les classes A et B. A a besoin de B (dépendance). Dans ce cas, A ne peut pas être implémenté sans B. Cependant, si A implémente en utilisant l'interface de B, il peut être implémenté sans B. L'injection d'un objet B via une interface est identique à A en utilisant B.

Regardez le code et reconnaissez la différence

Jusqu'à présent, nous avons expliqué le concept et le mécanisme de l'ID. À partir de là, nous examinerons le code réel et le comprendrons. Même si vous ne comprenez pas au début, vous devriez pouvoir le comprendre si vous le lisez plusieurs fois! En fait, je l'étais.

Le code à créer est composé des trois suivants. ・ Couche de référentiel ・ ・ ・ Couche de connexion à DB ・ Couche de service ・ ・ ・ Couche qui appelle le référentiel ・ Couche d'appel ・ ・ ・ Couche qui exploite l'ensemble

Code dépendant

Tout d'abord, examinons le code désordonné qui a des dépendances. (* Je pense avoir écrit ce code lorsque j'ai commencé la programmation.)

couche de référentiel La base de données créée est donnée directement au référentiel d'utilisateurs. (Mauvais: la couche du référentiel dépend de db. Je connais mysql)

package repository

type UserRepository struct {
	db sql.DB
}

func NewUserRepository() *UserRepository {
	//Création de DB
	db, _ := sql.Open("mysql", "root:@/database")
	//Création de la base de données directement dans le référentiel
	return &UserRepository{*db}
}

couche de service Le référentiel est nouveau et donné directement au service. (Mauvais point: la couche de service dépend du référentiel.)

package service

type UserService struct {
	ur repository.UserRepository
}

func NewUserService() *UserService {
	//Créer un référentiel
	ur := repository.NewUserRepository()
	//Référentiel créé directement au service
	return &UserService{*ur}
}


Couche d'appel Si le service est nouveau, un référentiel fixe et une base de données seront créés.

package main

func main() {

	us := service.NewUserService()
	//Gonyo Gonyo nous utilise
}

J'ai vu du mauvais code une fois. Vous pouvez voir que cela dépend beaucoup. Reconfirmée juste au cas où, une dépendance est un état dans lequel un objet connaît le contenu d'un objet.

Code qui a introduit DI

De là, nous allons regarder un très beau code qui introduit DI. (* Quand je vois pour la première fois le code qui utilise DI, il a l'air très sale ...)

J'ai oublié une chose importante avant de regarder le code. Il y a quatre manières de réaliser l'ID. 1.Constructor Injection 2.Setter Injection 3.Interface Injection 4.Field Injection

Cette fois, j'utiliserai 1 injection de constructeur. Je pense que c'est le meilleur pour moi.

couche de référentiel Dans NewUserRepository, db est utilisé comme constructeur. Par conséquent, cela ne dépend pas de db. De plus, return renvoie l'interface. Cela élimine également la dépendance entre la couche de référentiel et la couche de service.

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 nom de table (nom de colonne 1),Nom de colonne 2,……)")
}

couche de service NewUserService utilise une interface de référentiel dans son constructeur. Par conséquent, cela ne dépend pas du référentiel. De plus, return renvoie l'interface. Cela élimine également la dépendance entre la couche de service et la couche utilisateur.

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)
}

Couche côté utilisateur ur := repository.NewUserRepository(db) N'importe quelle base de données peut être acceptée tant qu'il s'agit d'une base de données.

us := service.NewUserService(ur) Tant que ur (référentiel) est un référentiel, tout référentiel peut être accepté.

Cela facilite son remplacement par un autre référentiel ou DB au moment du test. Comme ils ne se connaissent pas, il n'y a pas de dépendances et des modifications peuvent être apportées facilement.

(* Pour faciliter l'explication, la création de db est écrite en main)

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 nous utilise
}

Résumé

J'ai expliqué DI. En le mettant en œuvre ou en le regroupant dans un article comme celui-ci, L'intérieur de ma tête était très rafraîchissant. De plus, même si je pense le comprendre, je pense que ce ne sera peut-être pas possible s'il est mis en œuvre de manière inattendue. Si vous étudiez la DI, essayez de la mettre en œuvre vous-même.

Les références

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

[Objet obligatoire DI] Implémenter et comprendre le mécanisme de DI avec Go
Jouez avec le mécanisme de mot de passe de GitHub Webhook et Python
Implémenter et comprendre l'arborescence de recherche d'union dans Go
[Statistiques] Comprendre le mécanisme des graphiques Q-Q avec animation.
Visualisez la gamme d'insertions internes et externes avec python
[Ev3dev] Comprenons le mécanisme de contrôle LCD (écran)
Implémenter le modèle mathématique «modèle SIR» des maladies infectieuses avec OpenModelica (exemple de régulation répétée et de relaxation)
Implémenter le modèle mathématique «modèle SIR» des maladies infectieuses avec Open Modelica
Découvrez la puissance de l'accélération avec NumPy / SciPy
"Copie profonde" et "Copie superficielle" à comprendre avec le plus petit exemple
Mécanisme de pyenv et virtualenv
J'ai comparé la vitesse de Hash avec Topaz, Ruby et Python
[Statistiques] Visualisez et comprenez la méthode Hamiltonian Monte Carlo avec animation.
Pour améliorer la réutilisabilité et la maintenabilité des flux de travail créés avec Luigi
Essayer d'implémenter et de comprendre les arborescences de segments étape par étape (python)
J'ai essayé de créer un mécanisme de contrôle exclusif avec Go
J'ai étudié le mécanisme de connexion flask!
Comprendre le contenu du pipeline sklearn
À propos du type de base de Go
Coexistence de Python2 et 3 avec CircleCI (1.0)
J'ai remplacé le calcul numérique de Python par Rust et comparé la vitesse
Calculer l'itinéraire le plus court d'un graphe avec la méthode Dyxtra et Python
Vous pouvez également vérifier la communication de la base de données et du cache avec curl
Ajustez la largeur du bac de manière nette et précise avec l'histogramme de matplotlib et seaborn
La combinaison dorée d'Embulk et de BigQuery brille encore plus avec Digdag
J'ai vectorisé l'accord de la chanson avec word2vec et je l'ai visualisé avec t-SNE
Retrouvez les termes généraux de la séquence de Tribonacci en algèbre linéaire et Python
Lisez l'image du graphique avec OpenCV et obtenez les coordonnées du point final du graphique
L'histoire de la création d'une caméra sonore avec Touch Designer et ReSpeaker
Obtenez des visites d'articles et des likes avec l'API Qiita + Python
Créez DNN-CRF avec Chainer et reconnaissez la progression des accords de la musique
Obtenez et estimez la forme de la tête en utilisant Dlib et OpenCV avec python
Implémenter un modèle avec état et comportement (3) - Exemple d'implémentation par décorateur
J'ai mesuré la vitesse de la notation d'inclusion de liste, pendant et pendant avec python2.7.
Essayez de séparer l'arrière-plan et l'objet en mouvement de la vidéo avec OpenCV
Article qui peut être une ressource humaine qui comprend et maîtrise le mécanisme de l'API (avec du code Python)