It's a bit old article, but InfoQ's Domain Driven Design and Development Practices says:
The design dependency that the domain class depends on the Data Access Object (DAO) class and the service class depends on the domain class must "DI" for implementation by DDD. "I'm making it.
For Python, Inject is useful for achieving DI (Dependency Injection).
If you write a sample with roughly 100 lines, it will look like this.
# -*- coding: utf-8 -*-
import uuid
from abc import ABCMeta, abstractmethod
import inject
def config(binder):
binder.bind(UserRepository, UserMemoryRepository())
class User(object):
def __init__(self, identity, name):
self.identity = identity
self.name = name
class UserRepository(object):
u""" Base class of User Repository"""
__metaclass__ = ABCMeta
@abstractmethod
def store(self, user):
raise NotImplementedError
@abstractmethod
def find_by_identity(self, identity):
raise NotImplementedError
class UserMemoryRepository(UserRepository):
u""" User Repository on memory"""
def __init__(self):
self._users = {}
def store(self, user):
if not isinstance(user, User):
raise TypeError
self._users[user.identity] = user
def find_by_identity(self, identity):
return self._users[identity]
class UserRedisRepository(UserRepository):
u""" User Repository on Redis """
def store(self, user):
# TODO: write code here
pass
def find_by_identity(self, identity):
# TODO: write code here
pass
class UserService(object):
u""" User Service on Application Layer"""
repo = inject.attr(UserRepository)
def create_user(self, name):
user = User(uuid.uuid4(), name)
self.repo.store(user)
return user
def find_by_identity(self, identity):
return self.repo.find_by_identity(identity)
if __name__ == "__main__":
# Call once on application start
inject.configure(config)
user_service = UserService()
created_user = user_service.create_user('foo')
stored_user = user_service.find_by_identity(created_user.identity)
assert created_user == stored_user
To achieve the same thing without using ʻinject, you need to pass
repo as an argument to ʻUserService
, which makes the constructor of ʻUserService bloated as the number of dependencies increases. , ʻInject
can be used to write clearly. You can also use the @ inject.params
decorator to inject dependencies into the default arguments of the constructor.
It's a small library with only 300 lines, but it's very useful.
Recommended Posts