OOPの関数型プログラミング

良いコードが実行されるだけでなく、そのタスクを可能な限り説明するコードであると主張する人は誰もいないと思います(もちろん、これは主にビジネスロジックに適用されます)。 さらに、アルゴリズムの詳細ではなく、そのシグネチャ(名前、パラメーター、戻り値の型)、呼び出されるメソッドのシグネチャ、使用する変数によって記述します。 この場合、追加のコンテキストをメモリに保持することなく、メソッドの本体を上から下に読み取ることができます。





次のクラスを見てみましょう(トピックはやや珍しいですが、これにより誰かのコードを読むプロセスが退屈にならないように期待しています):



public class Invasion { private SearchCriterion _searchCriterion = (new GeniousCriterion()).or(new SexyCriterion()); private ExperimentProcedure _experimentProcedure = (new MockProcedure()).then(new WatchProcedure()); private _experience = new Experience(); private HumanBeing[] _humans; private ArrayList<HumanBeing> _chosenOnes; public void investigate() { updateChosenOnesList(); experiment(); } private void updateChosenOnesList() { _chosenOnes.clear(); for (HumanBeing human : _humans) if (_searchCriterion.satisfied(human)) _chosenOnes.add(human); } private void experiment() { for (HumanBeing human : _chosenOnes) _experience.push(_experimentProcedure.do(human)); } }
      
      







調査メソッドが何をするのかを調べるか、そのロジックが正しいことを確認する必要があります。 この場合、それが呼び出すすべてのメソッドのコードを理解したくありません。

メソッドupdateChosenOnesList。 この場合、メソッドの名前によって、その実装が_chosenOnesフィールドを更新する必要があると判断できます。 同時に、オブジェクトフィールドのリストを見ると、_humansの間で新しいフィールドが検索されると想定でき、_searchCriterion基準を使用して検索できます。 ただし、オブジェクトフィールドのリストをチェックし、それらの名前とメソッド名の関係をトレースすることはあまり便利ではありません。 状況は実験方法と似ています。



そして別の例


このクラスの別の実装オプションは次のとおりです(コメントを参照)。



 public class Invasion { // ….......... public void investigate() { //    :      ,    //   updateChosenOnesList(); _chosenOnes = search(_searchCriterion, _humans); //    ,    _experience.push(experiment(_experimentProcedure, _chosenOnes)); } private Experience experiment(ExperimentProcedure procedure, HumanBeing[] humans) { Experience exp = new Experience(); for (HumanBeing human : humans) exp.push(procedure.do(human)); return exp; } private ArrayList<HumanBeing> search(SearchCriterion criterion, HumanBeing[] humans) { ArrayList<HumanBeing> result = new ArrayList<HumanBeing>(); for (HumanBeing human : humans) if (criterion.satisfied(human)) result.add(human); return result; } }
      
      





実際、これは関数型プログラミングのアプリケーションでした。 このオプションの長所と短所が最初のものと比較してどうなるか見てみましょう。



長所


そうではありませんが、多くのマイナスがあります。 冗談。

まず、調査方法を読み、それが何をするのかを理解することが簡単になりました。もしそれが何をすべきか、そしてもしそうなら、それは正しいです。 同時に、フィールドのリストを含むメソッド自体の本体以外はどこも見ることができません。

次に、プライベートメソッドはオブジェクトの状態に依存しなくなりました。 実行の結果は、送信されたパラメーターによってのみ決定されることがわかります(つまり、呼び出し時にInvasionオブジェクトのすべてのフィールドの状態を監視する必要はありません-どのフィールドが転送され、どのフィールドが変更されているかを確認できます)。 同時に、引数として使用されるパラメーターは調査メソッドの本体で生成/初期化されました-つまり アルゴリズム全体と、侵略状態で発生したすべての変更が表示されます。



短所


パフォーマンス-悲しいかな。 同時に、調査メソッドが頻繁に呼び出されない限り、悲しみには意味がありません。

追加のパラメーターをメソッドに渡す必要があります-それらが多数ある場合、これは非常に重要です-4つ以上。 一方、メソッドが依存するパラメーターが多数ある場合、これはおそらくアーキテクチャの変更を検討する機会です(通常、必要なパラメーターを含むことができるSexyCriterionなどの新しいクラスを追加します)。



例について


一般的に言えば、この場合、プライベートメソッドは必要ありませんでした。 オブジェクトのコレクションを検索条件と手順のオブジェクトに完全に処理する機能を追加するだけで十分でした。 ただし、ここでは、主に例のコード量を削減するために、さまざまなタイプのオブジェクトに対する責任が最大限に分散されました。 そのようなモデルを構築する時間がないか、構築する必要がないことがよくあります(たとえば、要件が変更される可能性があり、最も単純なソリューションを適用する必要がある場合)。 そのような場合、機能スタイルによってコードの読み取りとサポートが簡素化される一方で、開発に費やされる時間は実質的に増加しません。



エピローグ


多数の行(たとえば、10行以上)を持つメソッドを含まず、同時にプライベートメソッドを必要としないコードを記述することができます(このようなメソッドは常に別の動作オブジェクトに転送できます)。 ただし、このようなコードを作成するプロセスは単純ではありません。

したがって、パブリックメソッドの複雑なコードを、パラメータのみに依存し、オブジェクトの状態を変更しないいくつかのプライベート関数メソッドに分割することができます。 この場合、パブリックメソッド(プライベートではない)のみがオブジェクトの状態を直接アクセス変更する必要があります。つまり、 インターフェイスの一部であるメソッド。 これにより、変数、メソッド、およびそれらのパラメーターに適切な名前が付けられていれば、複雑なアルゴリズムを一連のメソッドに簡単に減らすことができます。

そして、念のため、突然質問がある場合、OOPはどこにあり、関数型プログラミングはどこにありますか。 OOP-このパラダイムに基づいて、責任はオブジェクトの侵略、基準、手順、経験に分けられます。 関数型プログラミング-その助けを借りて、Invasionの内部ロジックが実装されます。この場合のプライベートメソッドは関数です(入力パラメーターのみに依存し、Invasionオブジェクトの状態を変更しません)。





ご清聴ありがとうございました! コメントにコメント、コメント、批判を書いてください。



2012年10月10日に投稿、コメントあり

これは、クラスの内部(補助)メソッドを使用してオブジェクトの状態を編集するだけでなく、これらのメソッドがオブジェクト自体の状態を読み取らないようにする(それらがすべてのパラメーターを引数として取得する)ことに注意してください

当然、この原則は絶対的なふりをするものではなく、プライベートメソッドにクラスの状態にアクセスできるようにした方が良い場合があります。 まず第一に、これは、異なる場所で同じ関数引数のセットを転送する(または関数の結果に基づいて同じフィールドのセットを編集する)という形でコードの重複が発生する可能性がある場合です。 たとえば、updateChosenOnesListメソッドを複数の場所で呼び出す必要があり、オブジェクトの同じ内部フィールドを渡す必要がある場合は、最初の例で間違いなくより適切に実装されます。

つまり この記事の目的は、エンコード方法を示すことではなく、メソッド関数の使用がもたらす利点に注意を引くことです。

引数の関数を編集する機能のトピックは、ここでは考慮されませんでした。



All Articles