web-dev-qa-db-ja.com

Python-ファクトリーメソッドとインジェクトフレームワーク-何がきれいですか?

私のアプリケーションで通常行うことは、ファクトリメソッドを使用してすべてのサービス/ dao/repo /クライアントを作成することです

class Service:
    def init(self, db):
        self._db = db

    @classmethod
    def from_env(cls):
        return cls(db=PostgresDatabase.from_env())

アプリを作成するとき

service = Service.from_env()

すべての依存関係を作成するもの

実際のデータベースを使用したくない場合のテストでは、DIを実行します

service = Service(db=InMemoryDatabse())

サービスはデータベースの作成方法を知っており、どのデータベースタイプを作成するか(InMemoryDatabseまたはMongoDatabaseでもかまいません)を知っているので、それはクリーン/ 16進数アーキテクチャとはかなり異なると思います。

私はクリーン/ 16進アーキテクチャでは私が持っていると思います

class DatabaseInterface(ABC):
    @abstractmethod
    def get_user(self, user_id: int) -> User:
        pass

import inject
class Service:
    @inject.autoparams()
    def __init__(self, db: DatabaseInterface):
        self._db = db

そして私はインジェクターフレームワークを設定して

# in app
inject.clear_and_configure(lambda binder: binder
                           .bind(DatabaseInterface, PostgresDatabase()))

# in test
inject.clear_and_configure(lambda binder: binder
                           .bind(DatabaseInterface, InMemoryDatabse()))

そして私の質問は:

  • 私のやり方は本当に悪いのですか?それはもうきれいなアーキテクチャではありませんか?
  • インジェクトを使用する利点は何ですか?
  • わざわざインジェクトフレームワークを使用する価値はありますか?
  • ドメインを外部から分離する他のより良い方法はありますか?
9
Ala Głowacka

別のデータベースを使用したい場合や、簡単な方法で柔軟に実行したい場合があるため、サービスを構成するには、依存性注入がより良い方法であると考えます

0
kederrac

最初の例は、「適切な」クリーン/ヘクスにかなり近いものです。不足しているのはコンポジションルートの考え方であり、インジェクターフレームワークがなくてもクリーン/ヘクスを実行できます。それがなければ、あなたは次のようなことをするでしょう:

class Service:
    def __init__(self, db):
        self._db = db

# In your app entry point:
service = Service(PostGresDb(config.Host, config.port, config.dbname))

これは、話をする相手に応じて、Pure/Vanilla/Poor ManのDIによって決まります。ダックタイピングや構造タイピングに頼ることができるため、抽象的なインターフェースは絶対に必要というわけではありません。

DIフレームワークを使用するかどうかは、意見と好みの問題ですが、その道を進むことを選択した場合、考慮できるpunqのような注入する他のより簡単な代替手段があります。

https://www.cosmicpython.com/ は、これらの問題を詳細に検討するための優れたリソースです。

0
ejung