Builder Pattern vs Abstract Factory Pattern

どちらもインスタンス生成に関わるパターン。
違い、というか、フレームワーク設計時にこの2つをどう使い分ければいいのか、よくわからなかったので、自分なりにまとめてみた。

Builder Patternは、インスタンスの生成プロセスを抽象化する(Abstract Builder)。プロセスはカプセル化され、それをシンプルなAPIにまとめ、利用可能にする。というわけで、様々な生成プロセスを持つクラス(Concrete Builders)をシンプルなAPIで作れるようになる。
『Createrは汎化されない、Createされる対象が汎化される』と理解してみる。

対して、Abstract Factory Patternは、あるクラス群と、その生成クラスを抽象化する(Abstract Models, Abstract Factory)。個々のクラスの生成プロセスはAPI群として、Abstrtact Factoryが提供する。つまり、インスタンス生成にかかわるAPIはあらかじめ固定される
『Createrは汎化される(FactoryA, FactoryB, FactoryC,...)、Createされる対象は汎化されない』と理解してみる。

Prototypeパターン

オブジェクトからオブジェクトを生成する設計。
phpではcloneキーワードでオブジェクトのシャローコピーを生成できる。

<?
  
  class Widget{
    public $header;
    
    function __construct(){
      $this->header = new Header($title); //<-- headerプロパティはHeaderオブジェクトの参照である
    }
    
    /*
     * phpのクローンキーワードは、オブジェクトのシャローコピーを行う
     * ディープコピーを行うときは以下のように__cloneメッソドを実装して、
     * それぞれのプロパティのクローンを作成する必要がある
     */
    function __clone(){
      $this->header = clone $this->header;
    }
    
    function title(){
      return $this->header->title;
    }
  }
  
  class Header{
    public $title = "default title";
  }
  
  $widget_a = new Widget;
  echo $widget_a->title() . "<br />"; //#default title

  $widget_b = clone $widget_a;
  echo $widget_a->title() . "<br />"; //#default title

  $widget_a->header->title = "hogehoge";

  echo $widget_a->title() . "<br />"; //#hogehoge
  echo $widget_b->title() . "<br />";//#default titleになる(__cloneが実装されていないとhogehogeのまま)
?>

colinuxでubuntuの環境を作る

ubuntu のイメージを直接colinuxのサイトから落としたやつだとシングルモードでの起動になってしまうので、インストーラー付属のイメージを使う。

ネットワーク接続はTAPで行う。Win側のネットワーク設定手順は割愛。ひとつだけ、ファイアーウォールが接続のジャマをするかもしれないので、注意。


以下、走り書きメモ。
最初のログインはID root, PW rootで。
nanoが入っているので、それを使って、まずはネットワークの設定。
ubuntu側はIP固定にする方向で。
etc/network/initerfacesを編集。んでもって、etc/resolve.confも編集。そして、/etc/init.d/networking restartする。

つぎに、aptの設定。ubuntuのバージョンがおそらく古いので、/etc/apt/sources.listを編集する。
編集の方法は、

deb http://old-releases.ubuntu.com/ubuntu jaunty main restricted universe multiverse
deb http://old-releases.ubuntu.com/ubuntu jaunty-updates main restricted universe multiverse
deb-src http://old-releases.ubuntu.com/ubuntu/ jaunty-updates main restricted universe multiverse

こんな感じで。詳しくはhttp://dqn.sakusakutto.jp/2011/06/ubuntu-apt-get-update.htmlとかで。

適切にsources.listを編集したら、apt-update apt-upgradeする。

これで、apt-get install hogehogeしまくれる状態になったはず。

Template/ Factory Method

Template method

ベースクラスにテンプレートメソッドを実装、他はサブクラスにデレゲーする、そういう設計
なので、ベースクラスの設計を分かりやすくしておくこと(コメント、ドキュメントとかを作っとく)
要は、デレゲーションさせる設計はテンプレートメソッドなのだと、言ってしまいたい。->ちょっとこれは違うな。デレゲーションは、クラスが他オブジェクトに、自分が受け持つメソッドの処理を引き渡す、すなわち、文字通り委譲する、その移譲するオブジェクトを抱えているという事なのだろう。先にも赤で書いたとおり、「サブクラスにデレゲート」というのが、Tempplate methodの本質か。

Factory Method

インスタンスの作成をファクトリーベースクラスのテンプレートメソッドコールで行う。ファクトリーメソッド(モデルクラスを実際に生成したりする)はサブクラスで実装する。

<?php

abstract class ModelBase{
  abstract function do_something();
  final function must_do_it(){
    echo "<br /><br />First of all, let's have a coffee.<br />";
  }
}

class SomeModel extends ModelBase{
  function do_something(){
    $this->must_do_it();
    echo "Next, we have on a chat each other.<br/>";
  }
}

class AnotherModel extends ModelBase{
  function do_something(){
    $this->must_do_it();
    echo "Next, we'll welcome another one.<br/>";
  }
  function do_something_else(){
    echo "Something Else<br/>";
  }
}

abstract class FactoryBase{
  abstract function factory_method();
  final function create(){ //<--クリエータークラス
    return $this->factory_method();//<-- インスタンス生成をサブクラスにデレゲーションする
  }
}


class Factory extends FactoryBase{
  function factory_method(){
    return new AnotherModel();
  }
}

class AnotherFactory extends FactoryBase{
  function factory_method(){
    return new SomeModel();
  }
}

$factory_a = new Factory;
$factory_b = new AnotherFactory;

$model_a = $factory_a->create();
$model_b = $factory_b->create();

$model_a->do_something();
$model_b->do_something();
$model_a->do_something_else();

?>

Bridge Pattern

機能(function, feature, facility)と実装(implementation)を分ける。
あるクラスに対して、異なる実装が必要な場合に有効な設計手段。


実装の基底クラスをbridgeによって結びつける。bridgeはデレゲーションによって実現される。
そして、機能拡張は浅いほど良い。

<?php
 class Display{
  protected $impl;//<-- ブリッジ
  function __construct($impl){
    $this->impl = $impl;
  }
   
  function open(){ //<--DisplayクラスのAPI. ブリッジを通じて実装される
    $this->impl->raw_open();
  }
  function content(){ //<--DisplayクラスのAPI. ブリッジを通じて実装される
    $this->impl->raw_content();
  }
  function close(){ //<--DisplayクラスのAPI. ブリッジを通じて実装される
    $this->impl->raw_close();
  }
  final function render(){ //<--- 機能拡張しない(final method)
    $this->open();
    $this->content();
    $this->close();
  }
}

abstract class DisplayImpl{ //<-- 実装の基底クラス
  abstract function raw_open();
  abstract function raw_content();
  abstract function raw_close();
}

class SomeDisplayImpl extends DisplayImpl{ //<-- Displayの実装
  function raw_open(){
    
    
  }
  function raw_content(){
    
  }
  function raw_close(){
    
  }
}

class AnotherDisplayImpl extends DisplayImpl{//<--さらに別のDisplayの実装
  function raw_open(){
    
  }
  function raw_content(){
    
  }
  function raw_close(){
    
  }
}

class CountDisplay extends Display{ //<-- Displayクラスの拡張クラス
  function multi_render($times){
    $this->open();
    for($i = 0;$i< $times;$i++){
      $this->render();
    }
  }
}

$impl_x = new SomeDisplayImpl();
$impl_y = new AnotherDisplayImpl();
$impl_z = new AnotherDisplayImpl();
$disp_a = new Display($impl_x);
$disp_b = new Display($impl_y);
$disp_c = new CountDisplay($impl_z);

$disp_a->render();
$disp_b->render();
$disp_c->multi_render(4);

?>

Adapter Pattern

名前の通り、アダプターの機能。
インターフェースの互換性を持たせるための設計手段。

<?
  /*
   * 変換されるクラス
   */
  class Banner{
    protected $title = "";
    function __construct($arg){
      $this->title = $arg;
    }
    function show_with_paren(){
      echo "((({$this->title})))<br />";
    }
    function show_with_aster(){
      echo "***{$this->title}***<br />";
    }
  }
  
  /*
   * アダプターインターフェース
   */
  interface  PrintAdapter{
    function print_weak();//<-- 新たなインターフェース
    function print_strong();//<-- 新たなインターフェース
  }
  
  /*
   * アダプター
   */
  class PrintBannerAdapter extends Banner implements PrintAdapter{
    function print_weak(){
      $this->show_with_paren();//<-- 二つのインターフェースを変換
    }
    function print_strong(){
      $this->show_with_aster();//<-- 二つのインターフェースを変換
    }
  }
  
  $print_banner = new PrintBannerAdapter("コーヒーの美味しさについて");
  $print_banner->print_strong();//<-- 新たなインターフェースを利用
  $print_banner->print_weak();//<-- 新たなインターフェースを利用
  
  echo "<hr />";
  
  /*
   * アダプター基底クラス
   */
  abstract class AnotherPrintAdapter{
    abstract function print_weak();//<-- 新たなインターフェース
    abstract function print_strong();//<-- 新たなインターフェース
  }
  
  /*
   * アダプター
   */
  class AnotherPrintBannerAdapter extends AnotherPrintAdapter{
    function __construct($title){
      $this->banner = new Banner($title); 
    }
    function print_weak(){
      $this->banner->show_with_paren();//<-- 変換前クラスにデレゲート
    }
    function print_strong(){
      $this->banner->show_with_aster();//<-- 変換前クラスにデレゲート
    }
  }
  
  $another_print_banner = new AnotherPrintBannerAdapter("ココアの温かさについて");
  $another_print_banner->print_strong();//<-- 新たなインターフェースを利用
  $another_print_banner->print_weak();//<-- 新たなインターフェースを利用
  
  
  
  
?>

Iterator Pattern

なんつうか、IteratorとかAggregateという名前がしっくりこない。Enumerable, Scannableとかのほうがしっくりくる気がする。
イテレーター(以下、スキャナーと書いてしまおう)はスキャンする対象を持っていて、そのインターフェースがhas_next, nextメソッド。集合体はスキャナーをCreateするインターフェースをもち、それがiteratorメソッド。


以下、コード;

<?
  /*
   * 集合体のインターフェース
   * イテレーターインターフェースを持つ
   */
  interface Aggregate{
    function iterator();
  }
  
  /*
   * 反復動作のインターフェース
   * 言い換えると、集合体のスキャンに必要なインターフェース
   */
  interface  MyIterator{
    function has_next();
    function next();
  }
  
  /*
   * フォトアルバム(写真の集合体)
   * スキャンクラスを持つ
   */
  class PhotoAlbum implements Aggregate{
    protected $photos = array(); //<--集合体はカプセル化されている
    protected $iterator;
    
    function __construct($args){
      $this->photos = $args;
    }
    function iterator(){
      return new PhotoAlbumIterator($this);
    }
    function odd_iterator(){
      return new PhotoAlbumOddIterator($this);
    }
    function get_photo_at($index){ //<--ゲッター
      return $this->photos[$index];
    }
    function size(){
      return count($this->photos);
    }
  }
  
  /*
   * アルバムのイテレーター
   */
  class PhotoAlbumIterator implements MyIterator{
    protected $photo_album; //<-- 数え上げる対象(PhotoAlbum)を知っている
    protected $index; //<-- 数え上げる為に必要
        
    function __construct($arg){
      $this->photo_album = $arg;
      $this->index = 0;
    }
    function has_next(){
      return $this->index < $this->photo_album->size();
    }
    function next(){
      $photo =  $this->photo_album->get_photo_at($this->index);
      ++ $this->index;
      return $photo;
    }
  }

class PhotoAlbumOddIterator extends PhotoAlbumIterator{
  function next(){
      $photo =  $this->photo_album->get_photo_at($this->index);
      $this->index = $this->index + 2;
      return $photo;
  }
}

  
$books = array("コーヒーの写真", "コーラの写真", "ファンタの写真", "山の写真", "ダイエットコークの写真");
$photo_album = new PhotoAlbum($books);
$iterator = $photo_album->iterator();
while($iterator->has_next()){
  echo $iterator->next() . "<br />";
}
echo "<hr />";
$odd_iterator = $photo_album->odd_iterator();
while($odd_iterator->has_next()){
  echo $odd_iterator->next() . "<br />";
}

  
?>