🛠Adapterパターンで結合と多重継承
Bridge/strategyの成れの果て
アダプタとブリッジの違い パッチと連結 力のブリッジ、技のアダプター
GoFのAdapterはインターフェース、デコレーターとの違い
Adapterは既存のクラスではインターフェースが合わないときに利用しろとなっている。ブリッジが複雑化した構造を整理しなおすために利用するのと違って、Adapterは既存のクラスをそのまま使うために使う。
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非破壊的なクラス
実行部のソースだけ拝借させていただく
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はとくに関係がない。