デザインパターンとは

デザインパターンとは何か疑問に思ったことはありますか? この記事では、設計パターンが重要である理由を説明し、それらをいつ、どこで使用するかを説明するPHPの例をいくつか示します。



設計パターンは、私たちが毎日直面するプログラミングの問題に対する再利用可能な最適化されたソリューションです。 設計パターンは、システムに単純に挿入できるクラスまたはライブラリではありません。 彼ははるかに多くです。 これは、適切な状況で実装する必要があるテンプレートです。 言語に依存しません。 優れたデザインパターンは、言語の特性に応じて、ほとんどの言語(すべてではないにしても)で使用できるようにする必要があります。 設計パターンを非常に慎重に使用する必要があることは非常に重要です。間違った場所に適用した場合、そのアクションは破壊的であり、多くの問題を引き起こす可能性があります。 ただし、適切な場所に適切なタイミングで適用すると、救世主になることができます。



設計パターンには主に3つのタイプがあります。



•構造

•生成

•行動



一般的な場合、 構造パターンはオブジェクト間の関係を処理し、それらの共同作業を促進します。



パターンを生成するとインスタンス化メカニズムが提供されるため、状況に最適な方法でオブジェクトを簡単に作成できます。



動作パターンはオブジェクト間の通信で使用され、より簡単で柔軟になります。



なぜそれらを使用する必要がありますか?



設計パターンは、原則として、プログラミングの問題に対するよく考えられたソリューションです。 多くのプログラマーは以前にこれらの問題に遭遇し、これらの「解決策」を使用して克服しました。 問題が発生した場合、すでに実証済みのソリューションを適用できるのに、なぜソリューションを再検索するのですか?





状況に応じて2つの異なるアクションを実行する2つのクラスを結合する方法を作成する必要があると想像してみましょう。 これらの2つのクラスは、さまざまな場所にある既存のシステムによって集中的に使用されるため、既存のコードを削除および変更することは困難です。 これに加えて、既存のコードを変更するには、変更されたコード全体をチェックする必要があります。 さまざまなコンポーネントで構築されたシステムでこの種の編集を行うと、ほとんどの場合、新しいエラーが発生します。 上記の代わりに、前述のタイプのシナリオを簡単に処理できる戦略テンプレートとアダプターテンプレートのバリアントを使用できます。



01 <?php 02 class StrategyAndAdapterExampleClass { 03 private $_class_one; 04 private $_class_two; 05 private $_context; 06 07 public function __construct( $context ) { 08 $this->_context = $context; 09 } 10 11 public function operation1() { 12 if( $this->_context == "context_for_class_one" ) { 13 $this->_class_one->operation1_in_class_one_context(); 14 } else ( $this->_context == "context_for_class_two" ) { 15 $this->_class_two->operation1_in_class_two_context(); 16 } 17 } 18 }
      
      





とても簡単ですよね? それでは、Strategyテンプレートを詳しく見てみましょう。



戦略テンプレート





cioinnervoice.wordpress.comウェブサイト所有者の厚意による画像



「戦略」テンプレートは、実行中に特定のコンテキストに基づいてプログラムが実行するアクションプランを決定できる動作設計テンプレートです。 2つのクラス内に2つの異なるアルゴリズムを配置し、実行時にどの戦略を使用するかを決定します。



上記の例では、クラスが処理されたときの$コンテキスト変数に応じて戦略が設定されます。 class_oneのコンテキストを指定すると、class_oneが使用され、その逆も同様です。



素晴らしいですが、どこで使用できますか?







現在、新しいユーザーレコードを更新または作成できるクラスを開発しているとします。 彼は同じ入力(名前、住所、携帯電話番号など)を必要としますが、状況に応じて、更新および作成時にさまざまな機能を使用する必要があります。 ここで、実行のために、おそらくすぐにif-else条件付きジャンプを使用できますが、このクラスが他の場所で必要な場合はどうでしょうか? 次に、この条件分岐演算子全体を完全に書き換える必要があります。 コンテキストを示すだけの方が簡単ではないでしょうか?



 01 <?php 02 class User { 03 04 public function CreateOrUpdate($name, $address, $mobile, $userid = null) 05 { 06 if( is_null($userid) ) { 07 //  ,     ,     08 } else { 09 //  ,    ,        10 } 11 } 12 }
      
      





「通常の」テンプレート「戦略」では、アルゴリズムを別のクラス内に配置しますが、この場合、別のクラスは非合理的なソリューションになります。 パターンに正確に従う必要はないことに注意してください。 オプションは、コンセプトが同じである限り機能し、これにより問題が解決します。



アダプタテンプレート





サイトwww.uxcell.comの所有者の許可を得て投稿した画像



「アダプター」テンプレートは、さまざまなインターフェイスを使用してクラスを再利用できる構造設計テンプレートであり、さまざまな呼び出しメソッドを使用するシステムで使用できるようにします。



また、クライアントクラスから受け取った入力の一部を変更して、Adapteeクラスの機能と互換性のあるものに変換することもできます。



これはどのように使用できますか?







アダプタクラスを参照するもう1つの概念は、 「ラッパー」です 。これにより、本質的にクラス内のアクションを「ラップ」し、適切な状況でこれらのアクションを再利用できます。 典型的な例は、テーブルクラスのドメインクラスを作成することです。 さまざまなクラスのテーブルを呼び出して、それらの関数を順番に呼び出す代わりに、アダプタークラスを使用してこれらすべてのメソッドを1つに埋め込むことができます。 これにより、必要なアクションを再利用できるだけでなく、同じアクションを別の場所で使用する必要がある場合にコードを書き直す必要もなくなります。



これら2つの実装を比較します。



アダプターなしのアプローチ

 1 <?php 2 $user = new User(); 3 $user->CreateOrUpdate( //inputs ); 4 5 $profile = new Profile(); 6 $profile->CreateOrUpdate( //inputs );
      
      





別の場所でもう一度行う必要がある場合、または別のプロジェクトでこのコードを使用する必要がある場合は、すべてをやり直す必要があります。



良いです



以下は、以下のようなアクションの反対です。

 1 <?php 2 $account_domain = new Account(); 3 $account_domain->NewAccount( //inputs );
      
      





この状況では、アカウントドメインクラスになるラッパークラスがあります。

 01 <?php 02 class Account() 03 { 04 public function NewAccount( //inputs ) 05 { 06 $user = new User(); 07 $user->CreateOrUpdate( //subset of inputs ); 08 09 $profile = new Profile(); 10 $profile->CreateOrUpdate( //subset of inputs ); 11 } 12 }
      
      





したがって、必要に応じてアカウントドメインを再度使用できます。さらに、ドメインクラスの下に他のクラスをラップすることもできます。



ファクトリメソッドテンプレート





www.lankanewspappers.comの所有者の厚意による画像



ファクトリメソッドパターンは、単語が意味するとおりのことを行う一般的なデザインパターンです。このクラスは、オブジェクトインスタンスのファクトリとして機能します。



このテンプレートの主な目的は、さまざまなクラスを1つの関数に組み込むことができる汎用プロシージャを埋め込むことです。 ファクトリメソッドに適切なコンテキストが提供されている場合、正しいオブジェクトを返すことができます。



これはいつ使用できますか?







Factory Methodテンプレートを使用する最適な状況は、1つのオブジェクトのいくつかの異なるバリアントが存在することです。 クラス「ボタン」があるとします。 このクラスには、ImageButton(画像ボタン)、InputButton(入力ボタン)、FlashButton(フラッシュボタン)などのさまざまなオプションがあります。 場所によっては、異なるボタンを作成する必要がある場合があります-これは、「ファクトリー」を使用してボタンを作成できる場所です。



3つのクラスを作成することから始めましょう。



 01 <?php 02 abstract class Button { 03 protected $_html; 04 05 public function getHtml() 06 { 07 return $this->_html; 08 } 09 } 10 11 class ImageButton extends Button { 12 protected $_html = "..."; //    HTML,        13 } 14 15 class InputButton extends Button { 16 protected $_html = "..."; //    HTML,      (<input type="button"... />); 17 } 18 19 class FlashButton extends Button { 20 protected $_html = "..."; //    HTML,    - 21 }
      
      





これで、ファクトリクラスを作成できます。



 01 <?php 02 class ButtonFactory 03 { 04 public static function createButton($type) 05 { 06 $baseClass = 'Button'; 07 $targetClass = ucfirst($type).$baseClass; 08 09 if (class_exists($targetClass) && is_subclass_of($targetClass, $baseClass)) { 10 return new $targetClass; 11 } else { 12 throw new Exception("The button type '$type' is not recognized."); 13 } 14 } 15 }
      
      





結果のコードは、たとえば次のように使用できます。



 1 $buttons = array('image','input','flash'); 2 foreach($buttons as $b) { 3 echo ButtonFactory::createButton($b)->getHtml() 4 }
      
      





出力は、すべてのボタンタイプのHTMLである必要があります。 そうすれば、状況に応じて作成するボタンを指定し、条件を再利用することもできます。



デコレータテンプレート









画像はwww.decoratorsdarlington.co.ukの厚意により掲載



デコレータパターンは、状況に応じて実行時にオブジェクトに新しい動作または追加の動作を追加できる構造設計パターンです。



目標は、高度な機能を特定の1つのインスタンスに適用し、同時にこれらの新しい機能を持たない元のインスタンスを作成できるようにすることです。 また、1つのインスタンスに対して複数のデコレータを組み合わせることができるため、各インスタンスに対して1つのデコレータへのバインドはありません。 このテンプレートは、サブクラスを作成する代わりに使用できます。サブクラスは、親クラスから機能を継承するクラスを作成することを指します。 コンパイル時の動作を追加するサブクラスを作成するのとは対照的に、装飾により、必要に応じて実行時に新しい動作を追加できます。



デコレータテンプレートを実装するには、次の手順を実行できます。



1.デコレータークラスのサブクラスとして元のコンポーネントクラスを選択します。

2. Decoratorクラスで、コンポーネントポインターをフィールドとして追加します。

3.「コンポーネント」ポインターを初期化するために、「コンポーネント」を「デコレーター」コンストラクターに移動します。

4. Decoratorクラスで、すべてのコンポーネントメソッドをコンポーネントポインターにリダイレクトします。

5.「Decorator」クラスで、動作を変更する必要のある「コンポーネント」のメソッド(すべてのメソッド)をキャンセルします。



これらの手順は、サイトの所有者の許可を得て投稿されましたen.wikipedia.org/wiki/Decorator_pattern



これはいつ使用できますか?







状況に応じて要求があった場合にのみ、新しい動作を必要とするオブジェクトに「デコレーター」テンプレートを使用するのが最も便利です。 HTMLレイアウト要素、ログアウトへのリンクがあり、現在のページに基づいてわずかに異なるアクションを実行したいとします。 これを行うには、「Decorator」テンプレートを使用できます。



最初に、必要なさまざまな「装飾」を設定します。



•メインページにアクセスして登録している場合、このリンクはh2タグで「ラップ」する必要があります。

•別のページで登録している場合、このリンクはアンダースコアタグで「ラップ」する必要があります。

•登録済みの場合、このリンクは太字のタグで「ラップ」する必要があります。

「シーナリー」を設定したら、それらをプログラムできます。



 01 <?php 02 class HtmlLinks { 03 // ,    html- 04 } 05 06 class LogoutLink extends HtmlLinks { 07 protected $_html; 08 09 public function __construct() { 10 $this->_html = "<a href=\"logout.php\">Logout</a>"; 11 } 12 13 public function setHtml($html) 14 { 15 $this->_html = $html; 16 } 17 18 public function render() 19 { 20 echo $this->_html; 21 } 22 } 23 24 class LogoutLinkH2Decorator extends HtmlLinks { 25 protected $_logout_link; 26 27 public function __construct( $logout_link ) 28 { 29 $this->_logout_link = $logout_link; 30 $this->setHtml("<h2>" . $this->_html . "</h2>"); 31 } 32 33 public function __call( $name, $args ) 34 { 35 $this->_logout_link->$name($args[0]); 36 } 37 } 38 39 class LogoutLinkUnderlineDecorator extends HtmlLinks { 40 protected $_logout_link; 41 42 public function __construct( $logout_link ) 43 { 44 $this->_logout_link = $logout_link; 45 $this->setHtml("<u>" . $this->_html . "</u>"); 46 } 47 48 public function __call( $name, $args ) 49 { 50 $this->_logout_link->$name($args[0]); 51 } 52 } 53 54 class LogoutLinkStrongDecorator extends HtmlLinks { 55 protected $_logout_link; 56 57 public function __construct( $logout_link ) 58 { 59 $this->_logout_link = $logout_link; 60 $this->setHtml("<strong>" . $this->_html . "</strong>"); 61 } 62 63 public function __call( $name, $args ) 64 { 65 $this->_logout_link->$name($args[0]); 66 } 67 }
      
      





これにより、たとえば次のように使用できるようになります。



 01 $logout_link = new LogoutLink(); 02 03 if( $is_logged_in ) { 04 $logout_link = new LogoutLinkStrongDecorator($logout_link); 05 } 06 07 if( $in_home_page ) { 08 $logout_link = new LogoutLinkH2Decorator($logout_link); 09 } else { 10 $logout_link = new LogoutLinkUnderlineDecorator($logout_link); 11 } 12 $logout_link->render();
      
      





ここでは、必要に応じて複数のデコレータをどのように組み合わせることができるかを確認できます。 すべてのデコレータは__callマジック関数を使用するため、元の関数のメソッドを呼び出すことができます。 現在メインページ内にあり、登録されていることを受け入れる場合、HTML出力は次のようになります。



 1 <strong><h2><a href="logout.php">Logout</a></h2></strong>
      
      







孤立テンプレート









ウェブサイトintoxicologist.wordpress.comの所有者の厚意による画像



「Loner」デザインパターンは、実行時に特定のクラスの1つの単一インスタンスと、その単一インスタンスへのグローバルアクセスポイントが存在することを保証する汎用デザインパターンです。



これにより、この単一インスタンスを使用する他のオブジェクトの「コーディネーションポイント」を設定しやすくなります。その変数は呼び出しに対して変更されないためです。



これはいつ使用できますか?











特定のインスタンスをあるクラスから別のクラスに転送する場合は、「Loner」テンプレートを使用して、コンストラクターまたは引数を介したこのインスタンスの通過を排除できます。 グローバルな$ _SESSION配列を模倣するSessionクラスを作成するとします。 このクラスは一度だけインスタンス化する必要があるため、次のような「Loner」テンプレートを実装できます。



 01 <?php 02 class Session 03 { 04 private static $instance; 05 06 public static function getInstance() 07 { 08 if( is_null(self::$instance) ) { 09 self::$instance = new self(); 10 } 11 return self::$instance; 12 } 13 14 private function __construct() { } 15 16 private function __clone() { } 17 18 //        19 ... 20 ... 21 ... 22 } 23 24 //    25 $session = Session::getInstance();
      
      





そうすることで、異なるクラスであっても、コードのさまざまな部分からセッションインスタンスにアクセスできます。 このデータは、すべてのgetInstance呼び出し中に保持されます。



おわりに



知っておくと便利なデザインパターンは他にもたくさんあります。 この記事では、プログラミング時に使用する最も有名なもののいくつかにのみ焦点を当てました。 他のデザインパターンについて読むことに興味がある場合は、Wikipedia Design Patternsページにこれに関する多くの情報が含まれています。 これで十分でない場合は、このトピックで最高の1つと見なされている「デザインパターン:再利用可能なオブジェクト指向ソフトウェアの要素」という本をいつでも読むことができます。



最後に、これらの設計パターンを使用して、問題を解決しようとしていることを常に確認します。 前述したように、これらの設計パターンは非常に慎重に使用する必要があります。それらは、間違ったコンテキストで使用すると事態を悪化させる可能性がありますが、適切に使用すると重要です。



この記事がお役にたちましたら、Envato MarketでのPHPスクリプトの提供をご覧ください。 開発をスピードアップし、最終結果を改善できる便利なスクリプトが数千あります。 予約システムAJAX連絡フォームニュースレターシステムなどがあります。



All Articles