2016-08-22 4 views
4

エリキシル剤で同じ機能を共有するデザインパターンは何ですか?エリキシル剤で同じ機能を共有するためのデザインパターンは何ですか?

たとえば、 私は、構造を「取得」し、構造を別の形式に「変換」し、それをいくつかのストレージに「プッシュ」するアプリを持っています。 私は、3つの変換ルールと3つのストレージでこのパイプラインを通過する3つの構造を持っています。

プロジェクトはgen_stageパッケージを使用し、それは以下の構造を有する:

(book) |producer| -> |transformer| -> |indexer| 
(article)|producer| -> |transformer| -> |indexer| 
(post) |producer| -> |transformer| -> |indexer| 

各段は、別個のモジュール、すなわちBook.Producer、Book.Transformer、Book.Indexerあります。

同じ垂線上のステージは、と同じものですが、異なるエンティティを使用していますが、です。私。 Book.Producer等、Article.Producerがデータベースから記事を取って、データベースから本を取っ

「データベースから取得」作品はかなり一般的であり、すなわち

alias Experimental.GenStage 

defmodule Books.Producer do 
    use GenStage 

    def start_link do 
    GenStage.start_link(__MODULE__, [], name: __MODULE__) 
    end 

    def init([]) do 
    {:producer, []} 
    end 

    def handle_demand(demand, processed) when demand > 0 do 
    events = Repo.all Book 
    {:noreply, events, processed ++ events} 
    end 
end 

すべてのパイプライン全体で再利用することができますトランスフォーマは、データベースから生成されたエンティティ上で関数を実行します。インデクサーは、トランスレコードを別のストレージにプッシュします。

多くの重複を伴​​う単純なアプローチでは、これらのすべての手順を実行している9(Book for 3、Article 3、Post for 3)モジュールを持つことができました。

類似の機能のビットを抽出し、それを使用するモジュール間で共有するにはどのようなオプションが必要ですか。

おそらく、初期化段階でパラメータを渡すか、9つのモジュールしか持たず、リファクタリング機能を別のモジュールに渡して構成することができます。ベストプラクティスは何ですか?

+0

これは、正確に何が共通しているのか、また9つの機能/モジュール間でデータの構造に特有なものが分からなければ、少し難解です。実際のコードを含めることはできますか? – Dogbert

+0

@Dogbert私は可能な限り明示しようとしましたが、実際のコードはあまりありませんが、 "共通"なものを示す例を追加しました。ありがとうございました! –

答えて

1

あなたが言及したケースの可能なオプションは、プロセスを開始するときにオプションとしてフェッチしようとしているスキーマモジュール(たとえば、BookPostなど)を渡すことです(たとえば、監視ツリーから) 。 start_linkの呼び出しでこれらのオプションを受け取ると、GenStage.start_linkを呼び出すときに2番目のパラメータとして渡すことができます。

これにより、GenStageの起動時に、これらのオプションが引数としてinitに渡されます。この時点で、そのモジュールを(例えばタプルのprocessedリストと一緒に)状態に置くことができます。そのため、すべてのhandle_demand呼び出しで渡されます。そこで、最後にRepo.allの呼び出しの引数として使用できます。

モジュールは他の値と同様に渡すことができます。また、コードを再利用するためにモジュールを使用することもできます。これは便利な例です。

フローの他の部分についても同様のアプローチを使用することができます。変化するものを見つけて、プロセスの開始時にオプションとして指定します。たとえば、変換関数は、2番目のステップのオプションの候補になります。あなたはそれを達成することができ、いくつかの方法があります。特定の機能を実現モジュールで

  • パス - 機能は、実際のモジュールに存在することを、いくつかの保証を得るためにBehaviours上のドキュメントをチェックアウトするには、
  • は、既存のモジュールでキャプチャされた関数を渡します(たとえば、&BookTransformer.transform/1)。
  • は、無名関数で渡します:fn data -> transform_all_the(data) end

同様に、関数はElixirの第一級市民です。それらは同じ値の回りに渡すことができます。これは、関数型プログラミング言語の共通コード再利用パターンです。

+0

変換関数をオプションとして「渡す」方法はありますか? 'BookTransformer'というモジュール名のようなものを渡し、' Transformer'が '.transform'関数に応答するようにするのは、暗黙のプロトコルのようなものです。 Transformerのプロトコルを定義し、渡すモジュールをそのプロトコルに準拠させることをお勧めしますか?どうもありがとう! –

+0

あなたはいくつかのオプションを持っています: *あなたが言及したように、あなたが望む機能を実装するモジュールを渡してください(機能を実装するための振る舞いを見てください) * '&BookTransformer.transform/1 ' *無名関数を渡す: 'fn data - > do_something_with(data)end' これらはすべて有効な値です: –

+0

Thiago、この追加情報でオリジナルの答えを更新してください。受け入れ、アイデアのために多くのおかげで! –

関連する問題