Help us understand the problem. What are the problem?

More than 5 years have passed since last update.


Python で DDD するなら Inject がオススメ


やや古い記事だけど、InfoQ のドメイン駆動設計・開発の実践には次のように書かれています。

ドメイン・クラスがData Access Object(DAO:データ・アクセス・オブジェクト)クラスに依存し、サービス・クラスがドメイン・クラスに依存するという設計上の依存関係がDDDによる実装に際してDIを"なくてはならない"ものにしています。

Python の場合、DI(依存性の注入)の実現には Inject が便利です。



# -*- 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

    def store(self, user):
        raise NotImplementedError

    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

    def find_by_identity(self, identity):
        # TODO: write code here

class UserService(object):
    u""" User Service on Application Layer"""
    repo = inject.attr(UserRepository)

    def create_user(self, name):
        user = User(uuid.uuid4(), name)
        return user

    def find_by_identity(self, identity):
        return self.repo.find_by_identity(identity)

if __name__ == "__main__":
    # Call once on application start

    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

inject を使わずに同様のことを実現するためには、UserService の引数に repo を渡す必要があり、依存関係が増えるたびに UserService のコンストラクタが肥大化してしまいますが、inject を利用するとスッキリと書けます。@inject.params デコレータを利用すれば、コンストラクタのデフォルト引数に依存性を注入することもできます。


Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Help us understand the problem. What are the problem?