その他の名前:オブジェクト指向AntiPatternなし「OOなし」
スケール:アプリケーション
リファクタリング:オブジェクト指向リエンジニアリング
関数分解は、アプリケーションを個別の機能モジュールに分割できるため、手続き型プログラミングの優れたプラクティスです。
残念ながら、機能の分解をクラス階層に直接反映することはできないため、記事で説明されている問題が発生することがあります。
多くの場合、手続き型プログラミングの経験豊富な開発者がオブジェクト指向言語でプログラムを設計および実装し始めると、アンチパターンが現れます。 開発者が他のサブルーチンを呼び出すメインサブルーチンを使用することに慣れている場合、クラス階層を完全に無視して、各サブルーチンをクラスとして実行する傾向があります(一般に、オブジェクト指向のアプローチ)。
結果のコードは、クラスとして実装された構造化プログラミング言語の構造に似ています。 そのようなコードは非常に複雑になる可能性があります。経験豊富な開発者は、オブジェクト指向アーキテクチャで昔ながらの手続き型プログラミング手法を繰り返す賢い方法を思いつくことができます。
CプログラマーがC ++で記述を開始するとき、またはCORBAインターフェイスを接続しようとするときに、ある種のオブジェクトテクノロジーを使用しようとするときに、アンチパターンに遭遇することがよくあります。 長い目で見れば、オブジェクト指向技術の学習に時間を費やすよりも、オブジェクト指向思考でプログラマを雇う方が簡単な場合があります。
アンチパターンの外観と結果の兆候
- 名前を持つクラスは、「 CalculateInterest 」や「 DisplayTable 」などの「関数」です。
- すべてのクラス属性はプライベートであり、クラス内でのみ使用されます。
- 手続き関数に似た単一のアクションを持つクラス。
- オブジェクト指向の概念に完全に準拠していない縮退アーキテクチャ。
- 継承やポリモーフィズムなどのオブジェクト指向の原則の非効率的な使用。 その結果、ソフトウェアの保守費用が非常に高くなる可能性があります。
- システムがどのように機能するかを明確に文書化できない場合があります。 クラスモデルには、システムのアーキテクチャを理解する意味はありません。
- 後続のコードの再利用の複雑さ(不可能な場合もあります)。
- ソフトウェアテストの複雑さ。
典型的な原因
- 開発者が手続き型からオブジェクト指向プログラミング言語に切り替える場合、オブジェクト指向アプローチの理解不足が一般的な慣行です。 OOPへの移行には、アーキテクチャ、設計、実装の開発におけるパラダイムシフトが必要であるため、個々の企業のオブジェクト指向アプローチへの完全な移行には、最大3年かかります。
- 採用されたアーキテクチャへのコンプライアンスの制御の欠如。 プログラマーがOOPに精通していない場合、アーキテクチャーがどの程度適切に設計されているかは問題ではありません。何をする必要があるかが単純に理解できません。 そして、アーキテクチャに定められた原則を遵守することに適切な注意を払わずに、手続き型プログラミングのよく知られた方法を使用してアーキテクチャを回避する方法を見つけます。
- 仕様の作成者/要件の説明がオブジェクト指向システムに十分に精通していない場合があります。 仕様を記述したり要件を分析したりする段階で、将来のシステムのアーキテクチャに関する仮定が行われると、「機能分解」などのアンチパターンにつながることがよくあります。
例外
オブジェクト指向のソリューションが必要ない場合は、機能の分解は受け入れられます。 この例外は、オブジェクト指向のインターフェイスを提供するために、本質的に純粋に機能的なソリューションがクラスでラップされている場合にも適用できます。
リファクタリング
それでもソフトウェアの初期基本要件を決定できる場合は、ユーザーの観点から最も重要なソフトウェア機能を記述する分析ソフトウェアモデルを作成する必要があります。 これは、コードベースのほとんどのソフトウェア構成の目的を決定するために非常に重要です。 アンチパターンリファクタリングのすべての段階で、行われた変更を詳細に文書化する必要があります。これにより、将来システムに同伴する人の生活が楽になります。
次に、既存のシステムの主要部分を含む設計モデルを作成します。 モデルの改善ではなく、できるだけ多くのシステムを記述するための基礎を作成することに焦点を当てます。
理想的な場合、設計モデルはほとんどのソフトウェアモジュールの存在を正当化します。 既存のコードベースの設計モデルを開発することは非常に重要です-プロセスは、システムが全体としてどのように機能するかを理解します。
システムの一部がすでに未知の理由で存在することを期待することは論理的です。 設計モデルから外れたクラスの場合、次の規則を使用します。
- クラスにメソッドが1つしかない場合は、既存のクラスの一部としてモデル化を試みてください。 ただし、多くの場合、クラスは他のクラスのヘルパークラスとして設計されており、メインクラスと組み合わせるよりも望ましいソリューションである場合があります。
- いくつかのクラスを新しいクラスに結合してみてください。 このような関連付けの目的は、異なる性質の機能を1つのクラスに統合することであり、これはより広いコンテキストをカバーします。 たとえば、情報のフィルタリングとデバイスの制御のためにデバイスへのアクセスを制御するクラスの代わりに、以前にいくつかのクラスにスプレーされたタスクを実行するメソッドを持つ1つのコントローラークラスを作成することをお勧めします。
- クラスに状態情報が含まれていない場合は、関数で書き換える必要があります。 おそらく、システムの一部は、制限なしにシステムのさまざまな部分から利用可能な機能として設計できます。
アーキテクチャを調べ、同様のサブシステムを見つけます-これらは再利用の候補です。 プログラムの保守の一環として、コードベースをリファクタリングして、同様のサブシステムでコードを再利用します(リファクタリングの詳細な説明については、スパゲッティコードアンチパターンソリューション(「スパゲッティコード」)を参照してください)。
例
機能分解の基礎は、たとえばJackson構造化プログラミング(JSP)メソッドを使用して、データ操作を実行する関数の順次呼び出しです。 多くの場合、関数はオブジェクト指向のコンテキストのメソッドです。 関数の分布は、異なるOOPパラダイムに基づいており、クラス内の関数と関連データの異なるグループ化につながります。
次の図の簡単な例は、クライアントのローン計算シナリオの手順バージョンを示しています。
計算シナリオ:
- 新しい顧客を追加します。
- クライアントアドレスを更新します。
- バイヤーのローンを計算します。
- ローン金利を計算する
- ローンの返済スケジュールを計算します。
- 新しい支払いスケジュールを保存します。
次の図は、ローン計算アプリケーションのオブジェクト指向ビューを示しています。 手続き関数はオブジェクトメソッドにマッピングされます。
関連ソリューション
システムの開発にすでに多くの労力が費やされている場合は、Blobアンチパターン問題の代替ソリューションに似たアプローチをとることができます。
クラスの階層全体を一度にボトムアップでリファクタリングする代わりに、クラス「メインサブプログラム」をクラス「コーディネーター」に拡張し、システムのすべての機能を管理できます。
次に、機能クラスを組み合わせて、その機能の一部を「コーディネーター」クラスに転送することにより、機能クラスを準オブジェクト指向クラスに変換できます。 結果は、より効率的なクラス階層になります。