微信搜索:碼農StayUpjava
主頁地址:gozhuyinglong.github.iogit
源碼分享:github.com/gozhuyinglo…github
咱們先來看一個模擬鴨子的遊戲:遊戲中會出現各類鴨子,它們一邊游泳戲水,一邊呱呱叫。算法
通過一番調研後: 已知的鴨子種類有:野鴨(Mallard Duck)、紅頭鴨(Redhead Duck)、橡皮鴨(Rubber Duck)。 已知的鴨子行爲有:游泳(Swim)、嘎嘎叫(Quack)、顯示鴨子的樣子(Display)。編程
下面是這些鴨子的外觀:設計模式
需求明確,開搞!微信
爲了可複用性,設計了一個鴨子超類Duck
,並讓各類鴨子繼承此超類:markdown
swim()
、quack()
方法,因爲每一種鴨子外觀不一樣,因此display()
指定爲抽象方法(固然該類也是抽象類)。display()
方法quack()
方法爲「吱吱叫」。下面是UML類圖: ide
咱們知道軟件開發的一個不變的真理是:「變化」!oop
如今要求增長一種鴨子行爲:飛行(Fly),該怎麼作呢?
若是繼續使用繼承,那麼橡皮鴨是不會飛行的,仍是須要重寫fly()
方法。以下:
那若是再增長一種鴨子:誘餌鴨(Decoy Duck),這是隻木頭鴨子,它即不會叫,也不會飛行......
看來繼承是不能知足需求了!
將fly()
方法和quack()
抽離出來,作成接口,讓擁有該行爲的鴨子對其進行實現。以下:
這彷佛解決了如今的問題!
但若是再增長100只鴨子呢?豈不是全部會飛行或會叫的鴨子,都要實現一遍,沒有達到代碼的複用性。並且一旦要修改某個行爲將是一件痛苦的事(好比將全部「吱吱叫」改爲「仿真呱呱叫」)……
有一個設計原則,剛好適用於上面模擬鴨子游戲的情況。
找出應用中可能須要變化之處,把它們獨立出來,不要和那些不須要變化的代碼混在一塊兒。
換句話說,若是每次來新的需求,都會使某方面的代碼發生變化,那麼你就能夠肯定,這部分的代碼須要被抽出來,和其餘穩定的代碼有所區分。
這即是策略模式的精神所在,下面咱們來看該模式的詳細介紹。
策略模式(Strategy Pattern)是一種行爲型模式。該模式定義一系列的算法,把它們一個個封裝起來,並使它們能夠相互替換。該模式讓算法的變化獨立於使用它的客戶。
Define a family of algorithms, encapsulate each one, and make them interchangeable.
該設計模式體現了幾個設計原則:
策略模式由三部分組成:
定義了全部策略的公共接口。上下文(Context)使用這個接口來調用某個具體策略(ConcreteStrategy)。
Strategy接口的實現,定義了一個具體的策略實現。
定義了Strategy對象如何來使用,是策略算法的調用者。
咱們使用策略模式實現上面模擬鴨子游戲。
定義飛行行爲接口
public interface Fly {
void fly();
}
複製代碼
用翅膀飛行實現類
public class FlyWithWings implements Fly {
@Override
public void fly() {
System.out.println("用翅膀飛行");
}
}
複製代碼
不會飛行實現類
public class FlyNoWay implements Fly {
@Override
public void fly() {
System.out.println("不會飛行");
}
}
複製代碼
定義鴨叫行爲接口
public interface Quack {
void quack();
}
複製代碼
呱呱叫實現類
public class QuackGuaGua implements Quack {
@Override
public void quack() {
System.out.println("呱呱叫");
}
}
複製代碼
吱吱叫實現類
public class QuackZhiZhi implements Quack {
@Override
public void quack() {
System.out.println("吱吱叫");
}
}
複製代碼
不會叫實現類
public class QuackNoWay implements Quack {
@Override
public void quack() {
System.out.println("不會叫");
}
}
複製代碼
定義鴨子抽象類
public abstract class Duck {
protected Fly fly;
protected Quack quack;
public void swim() {
System.out.println("正在游泳...");
}
public abstract void display();
public Fly getFly() {
return fly;
}
public Quack getQuack() {
return quack;
}
}
複製代碼
野鴨實現類
public class MallardDuck extends Duck {
// 野鴨用翅膀飛行,呱呱叫
public MallardDuck() {
this.fly = new FlyWithWings();
this.quack = new QuackGuaGua();
}
@Override
public void display() {
System.out.println("外觀是綠頭鴨");
}
}
複製代碼
紅頭鴨實現類
public class RedheadDuck extends Duck {
// 紅頭鴨用翅膀飛行,呱呱叫
public RedheadDuck() {
this.fly = new FlyWithWings();
this.quack = new QuackGuaGua();
}
@Override
public void display() {
System.out.println("外觀是紅頭鴨");
}
}
複製代碼
橡皮鴨實現類
public class RubberDuck extends Duck {
// 橡皮鴨不會飛行,吱吱叫
public RubberDuck() {
this.fly = new FlyNoWay();
this.quack = new QuackZhiZhi();
}
@Override
public void display() {
System.out.println("外觀是橡皮鴨");
}
}
複製代碼
誘餌鴨實現類
public class DecoyDuck extends Duck {
// 誘餌鴨不會飛行,也不會叫
public DecoyDuck() {
this.fly = new FlyNoWay();
this.quack = new QuackNoWay();
}
@Override
public void display() {
System.out.println("外觀是誘餌鴨");
}
}
複製代碼
編寫簡單測試類
public class Test {
public static void main(String[] args) {
MallardDuck mallardDuck = new MallardDuck();
mallardDuck.display();
mallardDuck.swim();
mallardDuck.getFly().fly();
mallardDuck.getQuack().quack();
System.out.println("-------------------");
DecoyDuck decoyDuck = new DecoyDuck();
decoyDuck.display();
decoyDuck.swim();
decoyDuck.getFly().fly();
decoyDuck.getQuack().quack();
}
}
複製代碼
輸出結果
外觀是綠頭鴨
正在游泳...
用翅膀飛行
呱呱叫
-------------------
外觀是誘餌鴨
正在游泳...
不會飛行
不會叫
複製代碼
完整代碼請訪問個人Github,若對你有幫助,歡迎給個Star,謝謝!