見出し画像

🛠Adapterパターンで結合と多重継承


Bridge/strategyの成れの果て

Flyweight (195): Strategy object often make good flyweights.ストラテジはしばし良いflyweightsとなる

アダプタとブリッジの違い パッチと連結 力のブリッジ、技のアダプター

Adapter ( 139) パターンは、 無関係なクラスを一緒に動作させることを目的としています。これは通常、システムが設計された後に適用されます。一方、Bridgeは、抽象化と実装が独立して変化するようにするために、設計の前段階で使用されます

GoFのAdapterはインターフェース、デコレーターとの違い

Adapterは既存のクラスではインターフェースが合わないときに利用しろとなっている。ブリッジが複雑化した構造を整理しなおすために利用するのと違って、Adapterは既存のクラスをそのまま使うために使う。

Decorator (175) は、インターフェースを変更せずに別のオブジェクトを拡張します。デコレータはこのように、アダプタよりもアプリケーションからの透過性が高いです。結果として、Decorator は、純粋なアダプタでは不可能な再帰的な合成をサポートします。

AdapterとDecorator実装の違いを Javaで見比べる

Adapterの本質はインタフェースの使い方にある

interface ProductPrice{
 public int getPrice();
}
class Product{
 private int cost;
 public int getCost(){
   return cost;
 }
}
class ProductAdapter implements ProductPrice{
 private Product product = new Product();
 public int getPrice(){
   return product.getCost();
 }
}

Decoratorについては定義を見なくてもソースのかたちをみればなんとなくどんなものだかはわかると思う。

public class DecoratorTest{
   public static void main(String[] argv){
       System.out.println(
           new WholesalePrice(
               new DoublePrice(
                   new WholesalePrice(
                       new DoublePrice(
                           new PrimePrice(120)
                           )
                       ,80
                       )
                   )
               ,200
               )
           .getValue()
           );
   }
}

継承関係があるので「再帰的に結合している」というのも見てよくわかる。

ブリッジとアダプターの違い

もともとBridgeとStrategyは形が一緒で、構造と振る舞いという対立軸があり結合がテーマとなっている。Decoratorが透過性の高い再帰的な結合をしてみせるのとは違って、Adapterはあくまでその形跡を残してご都合的に使う。flyweightは振る舞いのStrategyと関係が深く、Strategyが振る舞いならば、Decoratorは臓物(ガッツ)という格言がある。

Flyweight非破壊的なクラス

Flyweight パターンを採用すべき典型的な例は、不変なクラスを扱う場合である。不変なクラスとはインスタンスが生成された後にそのインスタンスの状態が変化しないようなクラスであり、Java では java.math.BigInteger や java.awt.Color などが挙げられる

実行部のソースだけ拝借させていただく

public class FlyweightTest {
   public static void main(String[] args) {
       StampFactory factory = new StampFactory();
       List<Stamp> stamps = new ArrayList<Stamp>();
       stamps.add(factory.get('た'));
       stamps.add(factory.get('か'));
       stamps.add(factory.get('い'));
       stamps.add(factory.get('た'));
       stamps.add(factory.get('け'));
       stamps.add(factory.get('た'));
       stamps.add(factory.get('て'));
       stamps.add(factory.get('か'));
       stamps.add(factory.get('け'));
       stamps.add(factory.get('た'));
       for(Stamp s : stamps){
           s.print();
       }
   }
}

フライ級ボクサー

GoFではテキストエディタの例がでてくる。加工や編集につかうこまい文字のようなデータも、オブジェクトになっている場合、そのまま作ると膨大にだぶるデータがでてくる。FlyWeight(フライ級ボクサー)はその名の通り、メモリ量のだぶつきを抑えてくれる。しかし、分かりにくい名前ばっかりだなGoF。

なるほど、flywieghtはアタマいい感じのパターンだ。メモ化を思い出す。

メモ化された関数は、以前の呼び出しの際の結果をそのときの引数と共に記憶しておき、後で同じ引数で呼び出されたとき、計算せずにその格納されている結果を返す。

イミュータブルという表現もある

もしオブジェクトがイミュータブルであったなら、オブジェクトの複製はオブジェクト全体の複製ではなく、単に参照の複製で済む。参照は通常オブジェクト自体よりもずっと小さいので(典型的にはポインタのサイズのみ)、メモリが節約でき、プログラムの実行速度もよくなる。

フライ級ボクサーから名前をとったflywieghtは、名前こそ稚拙な気はするが、実用面ではデザインパターンにしては珍しく分かりやすいし、抽象的な議論にも陥ることなく、メモリやパフォーマンスの話ができ、議論もしやすい。

キャプチャ
キャプチャ


キャプチャ


        get: function (make, model, processor) {
           if (!flyweights[make + model]) {
               flyweights[make + model] = 
                   new Flyweight(make, model, processor);
           }
           return flyweights[make + model];
       },

抜粋だが、flyweightsという配列を見て、同じものが入っていればそのまま返すし、なければFlyweightで新しいデータを作っている。実際のコードはFlyWeightFactoryというハッシュ内で行われる。

Javaの例はwikipediaにあるが

    Stamp get(char type){
       Stamp stamp = this.pool.get(type);
       if(stamp == null) {
           stamp = new Stamp(type);
           this.pool.put(type, stamp);
       }
       return stamp;
   }


基本は同じ。Flyweight自体がここではスタンプ、出現可能性も他のサンプルを見て分かったが

・ソース内にCHACHEとかコメントがある

・オブジェクトの有無を確認したうえで、無かったらニューしている

・getとかそういう名前がついている

・コメントにイミュータブルとか書いてある

となれば「Flyweightかも?」と叫んでもいい・

ストラテジとの類似性

    shipping.setStrategy(ups);
   log.add("UPS Strategy: " + shipping.calculate(package));
   shipping.setStrategy(usps);
   log.add("USPS Strategy: " + shipping.calculate(package));
   shipping.setStrategy(fedex);
   log.add("Fedex Strategy: " + shipping.calculate(package));

Bridge/strategyからのDecorator,Adapterは結合というキーワードをそれぞれ透過性とか構造と立ち振る舞いなどによって関連づけることができるが、flightweightはとくに関係がない。

また予言めいた格言でGoFのflyweightsはしめくくられる。

It's often best to implement State (30) and Strategy (315) objects as flyweights.ステートとストラテジの最良の実装はflyweights
となるであろう。

おまけ:アダプター二種類

アダプター二種類 オブジェクトコンポジションと多重継承


お願い致します