白話デザインモード_ポリシー・モード


ポリシーモデルは、名前を考慮して、異なる要求に対して異なるポリシーを採用して問題を処理します.
実際の「ポリシー」は通常アルゴリズムクラスタであり、同じ問題を処理したり、同じ動作を実行したりするのに複数のポリシーがある可能性がありますが、これらのポリシー間の切り替えはコードにハードコーディングで書かれている場合、かなり醜く、ポリシーモードはポリシー切り替えの動的メカニズムを提供します.すなわち、実行時に指定できます.
例えば、現在アヒルのシステムについて、抽象的な親系Duckがあり、中にはいくつかのアヒルの動作が宣言されています.例えば、鳴き、飛ぶ、泳ぐ、展示(ここでアヒルの動作はアルゴリズムクラスタです)、この抽象類に対してMallarDuck(緑の頭のアヒル)、RedheadDuck(赤の頭のアヒル)、RubberDuck(ゴムのアヒル)、今問題が出てきました:アヒルが飛ぶわけではありません.ゴムアヒルの例です.アヒルの鳴き声はそれぞれ違うかもしれません.後者の問題は、サブクラスで「呼ぶ」という方法を書き換えることで解決できますが、前の問題は解決できません.継承がコード多重化されているため、アヒルごとに「飛ぶ」という動作が含まれています.この問題を解決するために、「飛ぶ」という動作をDuck抽象クラスから分離して、Flyableインタフェースに抽象化してみて、「飛ぶ」という動作を必要とするアヒルはこのインタフェースを実現して、不要なのはこのインタフェースを実現しない~~表面的には問題を解決したようで、コード多重化を深刻に破壊した.インタフェースはメソッドのみを宣言するため、実装されていないため、各アヒルの実装クラスでは「飛ぶ」というメソッドを書き直さなければならない.この実装方式が完全に同じであっても、より大きな問題は、後で「飛ぶ」というメソッドを修正する場合、各アヒルの実装に1つずつ「飛ぶ」メソッドを修正しなければならないことであり、これは明らかに柔軟ではない.
ソフトウェア設計の基本原則:
一、アプリケーションに変化が必要な可能性のある点を見つけ、それらを独立させ、変化を必要としないコードと混同しないでください.
二、インタフェースに対してプログラミングを行い、実現に対してプログラミングを行うのではない.
三、組み合わせを多用し、継承を少なくする.
明らかに「飛ぶ」と「呼ぶ」の2つの方法はDuckクラスの変化の部分であり(他の方法が共通であれば)、第1の原則を用いて、それら2つを分離して、何に分離しますか?第2の原則を用いて結論を出すことができ,インタフェースに分離する.
 
// 
public interface FlyBehavior {
	void fly();	
}
// 
public interface QuackBehavior {
	void quack();
}

次に、この2つのインタフェースをそれぞれ実装する具体的なポリシーです.
//   
public class FlyNoWay implements FlyBehavior{
	public void fly(){
		System.out.println("Can't fly!");
	}
}
//    
public class FlyWithWings implements FlyBehavior {
	public void fly() {
		System.out.println("fly with wings!");
	}
}


//   
public class QuackGuagua implements QuackBehavior {
	public void quack() {
		System.out.println("   ");
	}

}
//   
public class QuackNoWay implements QuackBehavior {
	@Override
	public void quack() {
		System.out.println("   ...");
	}

}
//   
public class QuackZhizhi implements QuackBehavior {
	@Override
	public void quack() {
		System.out.println("   !");
	}

}

 
お客様はポリシーを使用する必要があります.ここでは3番目の原則に従い、Duckにこの2つのインタフェースの参照を追加し、performQuack()メソッドとperformFly()メソッドで上記のインタフェースの参照を使用し、「呼び出し」アクションと「飛ぶ」アクションを呼び出し、2つのsetメソッドを宣言します.この2つの参照を動的に設定するランタイムオブジェクト:
public abstract class Duck {

	FlyBehavior flyBehavior;
	QuackBehavior quackBehavior;
	
	public void setFlyBehavior(FlyBehavior flyBehavior) {
		this.flyBehavior = flyBehavior;
	}
	public void setQuackBehavior(QuackBehavior quackBehavior) {
		this.quackBehavior = quackBehavior;
	}
	
	public void swim(){
		System.out.println("    ...");
	}
	
	public abstract void display();
	
	public void performQuack(){
		quackBehavior.quack();
	}
	
	public void performFly(){
		flyBehavior.fly();
	}
}

 
テスト:
public class Main {
	public static void main(String[] args) {
		Duck duck1 = new MallarDuck();
      //      
		duck1.setFlyBehavior(new FlyWithWings());
		duck1.setQuackBehavior(new QuackZhizhi());
		duck1.display();
		duck1.performFly();
		duck1.performQuack();
		
		System.out.println();
		
		Duck duck2 = new RubberDuck();
      //      
		duck2.setFlyBehavior(new FlyNoWay());
		duck2.setQuackBehavior(new QuackGuagua());
		duck2.display();
		duck2.performFly();
		duck2.performQuack();
	}
}

 
まとめ:
ポリシー・モードの鍵は、変化部分の分離、インタフェース向けプログラミング、ポリシー・インタフェース・タイプ参照変数の含む、実行時に特定のポリシー・オブジェクトを動的に決定することです.