HeadFirstデザインモードを読む(一)


最近デザインモードのものを見ていますので、今日は以前見たHeadFirstデザインモードの資料を取り出してみました。  今日のまとめで、これから更新します。
これから:
    情景1:
        今はアヒルには二つの種類があります。MallardDuck、RedheadDuckはみんなおぎゃあと叫んで、泳いでいますが、外観は違います。コードの設計は以下の通りです。
    
アヒルの基質(ダクト)
public abstract class Duck {
	public void quack(){
		System.out.println("       !");
	}
	
	public void swim(){
		System.out.println("      !");
	}
	
	public abstract void display();
}
赤頭鴨(RedheadDuck)
public class RedheadDuck extends Duck {
	@Override
	public void display() {
		System.out.println("   !");
	}

}
鴨(MallardDuck)
public class MallardDuck extends Duck {
	@Override
	public void display() {
		System.out.println("        !");
	}

}
今は状況が少し変わりました。アヒルをflyできるようにします。
私たちはダクト類に直接fly()の方法を追加して、アヒルは全部飛んでしまいます。
今のダクトのコードは以下の通りです。
public abstract class Duck {
	public void quack(){
		System.out.println("       !");
	}
	
	public void swim(){
		System.out.println("      !");
	}
	
	public abstract void display();
	
        public void fly(){
		System.out.println("      !");
	}
ここで一つのことを見落としました。アヒルが全部飛んでいるわけではないです。
アヒルの新しい種類を追加します。RubberDuck(アヒルの消しゴム):
public class RubberDuck extends Duck {
	
	@Override
	public void quack() {
		System.out.println("        !");
	}

	@Override
	public void fly() {
		//   ,          
	}

	@Override
	public void display() {
		System.out.println("   !");
	}

}
このように見れば、一時的に満足できます。アヒルの消しゴムの「需要」が、もし私が新しいアヒルを追加したら、どうすればいいですか?
まずflyとquackをそれぞれ二つの違うインターフェースを作りましょう。
Flayable
public interface Flyable {
	void fly();
}
Quabale
public interface Quackable {
	void quack();
}
このように、flyがあれば、quackのアヒルはこの二つのインターフェースを実現しますが、新しい問題が現れました。これはいくつかの問題を解決しましたが、コードを多重化することができません。
この時、あなたはデザインモードを期待してあなたを救うかもしれません。
この段階で、設計モデルの第一原則を見ました。
             ,       ,                 。
現在知っているように、Duckはfly()、quack()の問題以外は正常です。
これらの「変化しない部分」を、「fly()」と「quack()」に分けます。
「おぎゃあ」インターフェース:QuackBehavior    
public interface QuackBehavior {
	void quack();
}
Quck(デフォルトの呼び方)
public class Quack implements QuackBehavior {

	@Override
	public void quack() {
		System.out.println("     !");
	}

}
スクエア(ガモの呼び方)
public class Squeak implements QuackBehavior {

	@Override
	public void quack() {
		System.out.println("     !");
	}

}
MuteQuck(アヒルのハスキー)
public class MuteQuack implements QuackBehavior {

	@Override
	public void quack() {
		//     ,   !
	}

}
「飛」のインターフェース:FlyBehavir
public interface FlyBehavior {
	void fly();
}
FlyNoWay(飛べない)
public class FlyNoWay implements FlyBehavior {

	@Override
	public void fly() {
		//     ,   !
	}

}
FlyWithwings(翼で飛ぶ)
public class FlyWithWings implements FlyBehavior {
	@Override
	public void fly() {
		System.out.println("      !");
	}

}
最後に私達のダクトは次のようになりました。
public abstract class Duck {
	private FlyBehavior flyBehavior;
	private QuackBehavior quackBehavior;
	public void swim(){
		System.out.println("      !");
	}
	
	public void performQuack(){
		quackBehavior.quack();
	}
	
	public void performFly(){
		flyBehavior.fly();
	}
	
	public abstract void display();

	public void setFlyBehavior(FlyBehavior flyBehavior) {
		this.flyBehavior = flyBehavior;
	}

	public void setQuackBehavior(QuackBehavior quackBehavior) {
		this.quackBehavior = quackBehavior;
	}
}
PS:上記では第二の設計原則を認識しました。
      ,       !
インターフェースは本当のインターフェースではなく、多状態であることが鍵です。スーパークラスのプログラミングに対しても理解できます。このように書く必要はなく、運行中に実際の状況によって本当の行動、方法を実行することができます。
上では第三の設計原則も認識させられました。
    ,    !
テストコード:
Duck duck = new RubberDuck();
		duck.setFlyBehavior(new FlyNoWay());
		duck.performFly();
上記の例は、実際にはデザインモードのポリシーモードを使用しています。