1. はじめに
デザインパターンの一般的な定義には立ち入らず、私が理解しているデザインパターンについて簡単に話します。私が理解しているデザインパターンの主な目的は、オブジェクト指向(クラス、インターフェース、など) コードの 拡張 や 再利用 、簡単な メンテナンス を可能にする機能。これら 3 つの特性により、多くの関数を 1 つのクラスに蓄積せず、より多くのクラスに割り当てる必要もあります。そのため、上記4つの目的を中心に20以上のデザインパターンがデザインされています。 PHP デザインパターンという本では 19 のデザインパターンについて説明していますが、実はほとんどのデザインパターンは思想やデザインという点では同じ考え方や形をしているので、誰でも理解できるように以下に分類してまとめておきます。この本を読んだ方がよいでしょう。この本の使用例は、コードをより単純にするために、インターフェイスを追加しないことを思い出してください。
(注:この記事は書籍「phpデザインパターン」を要約したものであるため、書籍の例については言及しましたが、時間の都合上、この記事では書きませんでした。電子書籍をご覧ください。例は各モードの紹介記事またはこの記事に追加されます)
2. クラスを作成する際に考慮すべきパターン
オブジェクト指向の最後の概念はクラスです。クラスはプロセス指向からオブジェクト指向に変換するための重要なステップです。次に、クラスを作成する際に、クラス間の依存関係をどのように実現するかが非常に重要な問題になります。以下のパターンがこの問題を対象としています。
1.ビルダーモード
コード内での new の出現を減らすように努めるべきです。これはクラスを作成するための重要な方法ですが、クラスのメソッド内ではなく、ビルダーまたはファクトリー内に出現するように努めるべきです。最初の理由は、このクラスの初期化メソッドがより面倒である可能性があるためです。 new が必要なだけでなく、新しいコンストラクターにパラメーターを渡す必要があり、それらのパラメーターにはオブジェクトが存在する可能性があります。この初期化操作は非常に長いです。2 番目の理由は、このクラスの要件が将来変更される可能性が非常に高いため、初期化操作を変更する必要があり、その変更操作が他のクラスでも実行されることです。これはクラス間の独立性の原則に準拠していません。
2. ファクトリーモード - 拡張ビルダーモード
ファクトリ パターンが多くのコードやフレームワークで言及されている場合、実際に実行されるのはビルダー パターンであり、ファクトリ パターンの意味は、ビルダー パターンをより柔軟にする抽象的なファクトリであると思います。ビルダー パターンの概念に従って、標準の作成プロセスを持つクラスがいくつかある場合、まず抽象プロジェクトを構築し、次に各具象クラスがこのクラスを継承します。ピザ ファクトリーがその良い例です。
3. 補足: サービスの概念 - 多くの PHP フレームワークと依存関係注入の実装の中核。依存性注入の方が重要なので、別の記事で説明します。
PHP の 2 つの主要なフレームワークである symfony と zend フレームワークを見ると、依存関係注入という非常に重要な概念があることがわかります。つまり、クラス間の依存関係の問題を解決する場合、その実装方法には非常に重要な概念があります。これはサービス、またはサービス コンテナと呼ばれる重要な概念です。私の理解では、これはファクトリ パターンに非常に似ており、ZF ではサービスを特定のファクトリに指定することもでき、ファクトリ クラスでは抽象ファクトリも実装できるため、この 2 つは概念的には似ていますが、実際には同じです。同じではありません。後ほど別途紹介させていただきます。
3. ニーズの変化や機能の追加があった場合
次のパターンにより、コードの再利用が容易になります
1.アダプターモード
関数が変更されるときは、クラスのインターフェースが変更されないことを保証する必要があると言います。これにより、クラスが変更されたときに、それを使用するためのコードやそのクラスを使用するためのコードを変更する必要がなくなります。しかし、結局のところ、この原則に違反するコードやクラスは存在するでしょう。たとえば、書籍で挙げられている例では、ErrorObject を分解する機能は、要件が変更されると logtocsvadapter クラスで実装される必要があります。理由(コードを変更できない、オープンソースではないなど)により、これを実行しませんでした。アダプター パターンは、この状況に対処するために使用され、拡張 (書籍での使用など) またはメンバー変数として使用することによって、要件を満たすインターフェイスを再実装できます。
2.デコレータモード
形式: 装飾されたクラスをそのメンバーとして使用し、そのメンバーを通じてメソッドを呼び出します。
クラスに機能を追加したいが、変更するのが怖い場合にこのパターンを使用できますが、このアイデアでは問題を根本的に解決できません。
もう 1 つの一般的なシナリオは、このクラスの一部の関数だけを他の人に見せたいが、すべての関数は見せたくない場合です。
3. メディエーターモード (イベントモードと同様)
形式: 複数の関連するクラスがメディエーター クラスをメンバーとして使用する場合、特定のメソッドを呼び出すと、メディエーターを介してメディエーターに登録されているすべてのクラスのステータスが変更されるため、登録されたクラスはメディエーターを呼び出すためのインターフェイスを実装する必要があります。
観察者に似ています。
登録が仲介者(イベントの登録マシンに相当)にハードコーディングされていることを除けば、構造はイベントパターンと似ていますが、その問題解決の考え方はイベントの特殊なケースであるため、仲介者と呼ばれますパターン。
1 つのクラスと、最初のクラスと概念上並列する別のクラスがあるとします (最初から存在するクラスである可能性もありますし、ニーズの変化に応じて出現するクラスである可能性もあります)。この 2 つのクラスがあります。あるクラスの状態を変更するには、別のクラスの状態を変更する必要があります。このとき、メディエーターが必要です。具体例はイベントモードで紹介します。
4. 関数をさらに多くのクラスに分散する
実際のプロジェクトでは、多くの機能を備えた「大きな」クラスを維持するのは非常に面倒です。これは、高凝集性と低結合性の原則に準拠しません。クラスの機能が増えると、よりプロセス指向になります。実際、オブジェクト指向で解決すべき主な問題は、より管理しやすい方法で関数をより多くのクラスに分散する方法です。しかし、実際には、クラスがより緊密に連携している必要があります。悪い意味で分割すると、より混沌としたデザインパターンが生まれる原因でもあります。たとえば、ある人がクラスの保守とこのクラスのテストを担当している場合、関数が変更されるたびにこのクラスのテスト コードを変更する必要があります。関数をより多くのクラスに分散すると、テスト コードを確実に変更できます。このクラスでは変更されません。
1.イベントモード(詳しくは別記事で紹介します)
私を含めて多くの人は、イベントがウィンドウプロセスに残る、マウスやボタンをクリックするとイベントが発生し、そのイベントに登録されているすべてのオブジェクトが変更されるという印象を持っています。ビュー、または自分で定義した関数の場合もあります。メディエーター モードもイベント モードと似ていますが、テーブルやヒストグラムなど、メディエーターに登録されているものはすべて同等の関係になります。棒グラフを短くしたり長くしたりすると、テーブルの内容が変化します。しかし、一般的なアプリケーション ロジックでは、イベント パターンとメディエーター パターンはどのように使用されるのでしょうか?
上記のイベントの意味は置いといて、上記はイベントの特殊なケースです。ここでは、イベントのより一般的な使用法を説明します。実際、イベントは本質的にメディエーター パターンであり、メディエーターは、変更する必要があるクラスに登録されたコンテナーを配置します。これは、イベントでイベントに渡されるオブジェクトに相当します。ただし、一部のクラスはメディエーター パターンに設計されていません。つまり、クラスはメディエーターのメンバーを保存しません。これは、この要件を予期していなかったからかもしれません。あるいは、このメカニズムをクラスに追加するのが面倒だと思ったからかもしれません。代わりに、同じ機能をクラスの外で実装できるイベント パターンを選択しました。 (つまり、仲介パターンをイベントパターンに変換することができます。 イベントパターンはクラス内でのトラブルを回避しますが、一連のイベントメカニズムを提供する必要があり、クラス外の仲介よりも面倒ですが、クラスの外には、多くの既成のメディエーター実装があり、基本的に各フレームワークはこのメカニズムを実装しており、symfony は symfony
以外のフレームワークでもこのコンポーネントを使用できます。上記のビューインターフェイスの操作に加えて、他の例はあまり直感的ではなく、イベントの名前に当てはまらない可能性があります。その主な機能は、イベントモードのコード構造を介してより適切です。コードを分割できるため、管理が容易になります。したがって、それを理解するということは、その出来事の一般的な意味を忘れることです。より複雑なロジックの例を考えてみましょう。ご存知のとおり、電話会社はユーザーの通話記録に基づいて料金を計算します。これはユーザーのさまざまなパッケージや使用地域によって異なります。ロジックの長いリストです。判定コードをクラス内に記述する必要がありますか?これは明らかに私たちの原則と一致しないため、イベント パターンの form を使用して (単なる形式であることを繰り返し強調します)、ロジックをさまざまなカテゴリに分割します。すべての電話サービスをリスナーとして登録し、if ステートメントを使用して各通話レコードがどのビジネスに属するかを決定します。その後、それらのビジネスにディスパッチし、リスナーは請求オブジェクトを取得して変更し、最終的に請求オブジェクトが最終的な請求情報になります。 。イベント モデルを通じて、さまざまな処理ロジックをリスナー オブジェクトに分離します。これにより、将来の拡張がより便利になります。
上記の例は、リスナーを介してオブジェクトを変更することもできますが、取得したオブジェクト情報を使用して関連する操作を実行することもできます。たとえば、ブログの投稿をブログガーデンに公開するには、保存する必要があるなど、多くの操作が必要になります。データベース、反転操作を実行する必要性、およびタグ操作を実行する必要があるため、ホームページに公開する場合は、いくつかのリスナーを使用してブログ投稿の公開操作を監視する必要があります。 Post オブジェクト自体は Post オブジェクトを変更するのではなく、Post オブジェクトの情報を利用して動作します。
より一般的な話に戻りますが、イベント パターンは主にプラグインで使用され、もちろん広い意味ではプラグインでも使用されます。これは symfony の紹介です。プロジェクトにプラグイン システムを提供する場合、プラグインは他のプラグインを妨げずにメソッドを追加したり、メソッドの実行前または実行後に何かを実行したりできる必要があります。これは、単一継承および多重継承で解決するのは簡単な問題ではありません (PHP では可能でしたか) には、独自の欠点があります。
上記の意味で、イベントはよりスケーラブルな方法でオブジェクトを処理および処理するためのメカニズムであり、このメカニズムを利用したいときにいつでもイベントを使用でき、既存のフレームワークのイベント コンポーネントの助けを借りて、両方を行うことができます。オブザーバーとメディエーターはイベント パターンに変換されるため、イベントは実際に非常に一般的に使用され、C# でのイベントの強調にも反映されます。イベントの使用方法を学ぶには、symfony イベントのドキュメントを参照することもできます。
2. オブザーバーモード
形式: $this->obserber->update($this)、メディエーターの形式は $this->mediator->chage($this,array('band'=>$newname)) 。 2 つの異なる機能要件を満たすだけであることがわかります。これらはどちらもイベントで置き換えることができ、前者は更新イベントを送信し、後者はchangeBandNameイベントを送信し、受信オブジェクトの名前を確認することによって変更が実装されます。
3. デリゲートモード
他のオブジェクトに割り当てたり委任したりすることで、委任デザインパターンは
決定(if文)や複雑な機能をコアオブジェクトから削除することができます。 C# の委任の概念と同様に、C# では関数の形式を使用してデリゲートをパラメーターとして他の関数に渡し、それによって機能を他の方程式に分割します。オブジェクト指向における委任とは、機能をデリゲート クラスに分割することです。
形式:委任クラスの中に委任クラスのメンバ変数があります。4.戦略モード
ベストプラクティスは、オブジェクトベースのアプリケーションに適用される自己完結型アルゴリズムで構成される交換可能なオブジェクトを作成する場合には、Strategy パターンを使用することです。
形式的にも意味的にも基本的に委任モードと同じですが、本の例の委任モードは $this->playlist を委任モードに渡しますが、ストラテジー モードは $this 全体をストラテジーに渡します。モード。
戦略パターンも重要な意味を持ちます。クラスのメソッドが頻繁に使用されない場合は、そのクラスをクラステスト中に毎回テストする必要がないように、戦略パターンに変換できます。
5. エージェントモード
エージェントモードは、「代理店」という意味が与えられている限り、さまざまな形をとることができます。この本では、エージェントはデコレーターの継承形式を通じて実装されます。
5. その他
以下は非常に一般的なパターンです
1. オブジェクト指向テンプレートの固有パターン
詳しくは紹介しませんが、抽象クラスやインターフェースと同じ考え方です。
2. ファサード
ファサードという言葉は、一部のフレームワークのクラスの名前付けで非常に一般的で、プロセス指向のプロセスにおける関数の役割に似ており、特定の関数の一連のコードをクラス内の静的メソッドにカプセル化します。クラスにはこの 1 つのメソッドしかありません。
3. パブリック メソッドはクラスに抽象化されます - データ アクセス オブジェクト パターン
パブリックメソッドをクラスに抽象化するのはオブジェクト指向の基本原則です。関数が複数のエンティティや関数で使用できる場合は、別のクラスを作成する必要があります。それは、上記の記事で述べた依存性注入と同じになります。
データアクセスオブジェクトパターンもこのパターンの基本実践です。 zend famework のガイド http://framework.zend.com/manual/current/en/in- Depth-guide/preparing-db-backend.html と併せて理解することができます。基本的には、テーブルゲートウェイもこの分野では成熟したモデルですが、これはデータベース自体の接続操作をクラス間の操作によってのみ実現できます。 . 接続については、また別の記事で書きます。
4. システムに必要なのは 1 つだけです - 単一要素モード
このパターンもよくあります
6. 本書の重要な文章についてのメモ
1. 異なるオブジェクトの接続が簡素化の目標です