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