2016-08-07 18 views
1

funのプログラミングでは、依存関係の管理が最小限に抑えたいという退屈な仕事のように感じています。 After reading this、私は、依存関係のインスタンスがキー文字列で検索されることによって、スーパー些細な依存性注入器を作ってみた:遅延呼び出しのためのPython依存性注入

def run_job(job, args, instance_keys, injected): 
    args.extend([injected[key] for key in instance_keys]) 
    return job(*args) 

私のプログラムでのコールは常に遅延し(ここで、関数定義されているので、このチープ・トリックの作品例えば、イテレータに)その引数とは別に保存されているハンドル:

jobs_to_run = [[some_func, ("arg1", "arg2"), ("obj_key",)], [other_func,(),()]] 

理由があるため、すべてのイベントをスケジュールする必要があり、中央main loopです。それはすべての依存関係への参照を持っているので、"obj_key"用噴射が辞書オブジェクトに渡すことができ、例えば:

# inside main loop 
injection = {"obj_key" : injected_instance} 
for (callable, with_args, and_dependencies) in jobs_to_run: 
    run_job(callable, with_args, and_dependencies, injection) 

イベント(ユーザ入力等)を発生しそう

は、メインループは update()を呼び出すことその入力に反応する特定のオブジェクトに対して、 main loopがリソースがあるときにスケジュールするジョブのリストを作成します。私には、 キーリファレンスにはどんな従属関係もありません。 他の人は、すべてのオブジェクトが直接の関係を形成するのではなく、注入するものです。

私はgame clock engine to run them on its own accordのすべての呼び出し可能関数(関数)を遅延定義しているので、上記の単純なアプローチでは複雑さがほとんどなくなりました。それでも、文字列でオブジェクトを参照する必要があります。同時に、依存関係を回避するのは臭いものでしたが、constructor or setter injectionはおそらく最も大きなdependency injection librariesのように過度の攻撃になります。 なまけが定義されている呼び出し可能に依存性を注入する特殊なケースでは

は、現存するが、より表現のデザインパターンですか?

+1

'kwargs'構文を使って名前付きの関数パラメータを使用し、それを注入可能な' dict'として扱うというあなたの現在のアプローチを改良することができます。そうすれば、生の文字列は関数のパラメータとして明示的になります。 – user268396

答えて

1

私は、依存関係の管理が最小限に抑えたいという退屈な仕事のように感じています。

まず、依存性注入が依存性管理の雑用を最小限に抑える手段であると仮定しないでください。それは離れていない、それはちょうど別の場所と時間に延期され、おそらく他の誰かに委任されます。

あなたが構築しているものが他の人によって使用されるとすれば、あなたのユーザーはあなたの「注射可能物」にバージョンチェックの何らかの形式を含めることが賢明でしょう。予想されるものと一致します。

存在感がより表現的なデザインパターンがありますか?

あなたの方法私はそれが本質的Strategy-Patternで理解し、そのジョブのコード(呼び出し可能)であるいくつかの具体的なオブジェクトのいずれかのメソッドを呼び出すに依存しています。あなたがそれを行う方法は完全に合理的です - それは効果的です。

読みやすく管理しやすくするために、もう少しフォーマル化したいと思うかもしれません。

from collections import namedtuple 

Job = namedtuple('Job', ['callable', 'args', 'strategies']) 

def run_job(job, using=None): 
    strategies = { k: using[k] for k in job.strategies] } 
    return job.callable(*args, **strategies) 

jobs_to_run = [ 
    Job(callable=some_func, args=(1,2), strategies=('A', 'B')), 
    Job(callable=other_func, ...), 
] 

strategies = {"A": injected_strategy, ...} 
for job in jobs_to_run: 
    run_job(job, using=strategies) 

# actual job 
def some_func(arg1, arg2, A=None, B=None): 
    ... 

あなたはコードがまだ同じことを行い、それが瞬時に読みやすく、そしてそれはrun_jobで仕事()オブジェクトの構造に関する知識を集中さ見ることができるように。引数の数が間違っていれば、some_funcのようなジョブ関数の呼び出しも失敗し、明示的にリストされ名前付きの引数があるため、ジョブ関数のコード化とデバッグが容易になります。

0

注入オブジェクトを常に注入する必要がない場合、つまり注入関数が呼び出されるたびに依存関係の新しいインスタンスを作成しても問題ない場合は、@autowired decoratorが役に立ちます。努力しない。

あなたの機能を飾るほど簡単です。

あなたは、このようなコードを回す:私はプロジェクトを維持

class Example: 
    @autowired(lazy=True) 
    def __init__(self, *, lazy_service: Service): 
     self.service = service 

    # actual code 

:この中へ

class Example: 
    def __init__(self, *, lazy_service: Service = None): 
     self._service = lazy_service 

    @property 
    def service(self) -> Service: 
     if self._service is None: 
      self._service = Service() 

     return self._service 

    # actual code 

。私はデコレータを作成して、関数呼び出し元が依存関係自体を提供していないときに依存インスタンスを初期化するために使用される、不必要で反復的なコードを自動化しました。