設計模式:HelloWorld之策略模式
一.概述
策略模式 定義了算法族,分別封裝起來,讓他們可以互相替換,此模式讓算法的變化獨立於使用算法的客戶。
策略模式的三要素:
抽象策略角色: 策略類,通常由一個接口或者抽象類實現。
具體策略角色:包裝了相關的算法和行為。
環境角色:持有一個策略類的引用,最終給客戶端調用。
二.案例驅動
提出問題:要求做出一套模擬鴨子的遊戲,遊戲中會出現各種鴨子,它們一邊遊泳,一邊呱呱叫。
分析:根據OO設計思想,無非就是使各種鴨子實現自己相應的功能即可,如鴨子遊泳,鴨子呱呱叫。
解決方案1.0:設計一個接口(Duck),然後根據需要完成不同的實現,如紅頭鴨,綠頭鴨。。。。
public interface Duck {
public abstract void quack();
public abstract void swim();
public abstract void display();
}
public MallardDuck implements Duck{
public abstract void quack(){
System.out.println("呱呱~~");
}
public abstract void swim(){
System.out.println("歡快的遊泳~~");
}
public abstract void display(){
System.out.println("綠頭鴨~~");
}
}
public RedHeadDuck implements Duck{
public abstract void quack(){
System.out.println("呱呱~~");
}
public abstract void swim(){
System.out.println("歡快的遊泳~~");
}
public abstract void display(){
System.out .println("紅頭鴨~~");
}
}
突然增加一個新的需求,要求有野鴨,除了具有這兩個功能外,還會飛(fly),同時還有一種橡皮鴨,叫聲時吱吱。。
此時該方案便暴露了一下缺點。。。。
缺點:牽一發而動全身,我們很難知道所有鴨子的行為,當針對有些實現需要添加新的功能時
解決方案1.1
為了更加靈活,面向接口編程。
public interface Flyable {
public abstract void fly();
}
public interface Swimable {
public abstract void swim();
}
public interface Quackable {
public abstract void quack();
}
public RedHeadDuck implements Quackable implements Swimable {...}
public WildDuck implements Quackable implements Swimable implements Flyable {...}
如果有一萬種鴨子,這種方式簡直不敢想象,重復代碼太多!
解決方案2.0
采用策咯模式解決此問題。
step1:把會變化的部分取出來,並封裝起來,好讓其他代碼不受影響。
step2:封裝行為的大局觀
step3:代碼實現
抽象策略角色
// 飛行行為
public interface FlyBehavior {
public abstract void fly();
}
// 叫聲行為
public interface QuackBehavior {
public abstract void quack();
}
具體策略對象
// 橡皮鴨叫
public RubberDuckBehavior implements QuackBehavior {
public abstract void quack(){
System.out.println("吱吱~~");
}
}
// 野鴨叫
public WildDuckBehavior implements QuackBehavior {
public void quack(){
System.out.println("嘎嘎~~");
}
}
// 大黃鴨叫
public YellowDuckBehavior implements QuackBehavior {
public void quack(){
System.out.println("呱呱~~");
}
}
// 不會飛
public FlyNoWay implements FlyBehavior {
public void fly(){
System.out.println("不會飛~~");
}
}
// 用翅膀飛
public FlyWithWings implements FlyBehavior {
public void fly(){
System.out.println("用翅膀飛~~");
}
}
// 螺旋槳飛
public FlyLikePlane implements FlyBehavior {
public void fly(){
System.out.println("用螺旋槳~~");
}
}
環境角色
抽象類
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 performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public abstract display() {}
public void swim() {
System.out.println("鴨子天生會遊泳!");
}
}
實現
public class WildDuck implements Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public WildDuck() {
// 默認會飛,野鴨叫嘎嘎
this.flyBehavior = new FlyWithWings();
this.quackBehavior = new WildDuckBehavior();
}
// 動態設定行為
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void display() {
System.out.println("這是一只野鴨!");
}
public void swim() {
System.out.println("鴨子天生會遊泳!");
}
}
需求改變:野鴨的翅膀受傷,不會飛了
public static void main(String[] args) {
Duck duck = new WildDuck();
duck.setFlyBehavior(new FlyNoWay());
duck.performFly();// 輸出:不會飛~~
}
需改改變:新增一只火箭鴨,能飛到太空,不會遊泳,外形像火箭一樣,叫嘎嘎
public RocketDuckFlyBehavior implements FlyBehavior {
public void fly(){
System.out.println("飛到太空~~");
}
}
public class RocketDuck implements Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public WildDuck() {
// 默認會飛,野鴨叫嘎嘎
this.flyBehavior = new RocketDuckFlyBehavior();
this.quackBehavior = new WildDuckQuackBehavior();
}
// 動態設定行為
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public abstract display() {
System.out.println("外形像火箭~~");
}
public void swim() {
System.out.println("不會遊泳");
}
}
三.策略模式的優缺點
優點:
1.策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行為族。恰當使用繼承可以把代碼轉移到符類,從而避免重復代碼 。
2.在策略模式中利用組合和委托來讓環境角色擁有執行算法的能力,這也是繼承的一種更輕便的替代方案。
3.提供了對開放—封閉原則的完美支持,將算法封裝在獨立的strategy中,使得它們易於切換,易於理解,易於擴展
4.利用組合、委托和多態等技術和思想,可以有效地避免多重條件選擇語句
缺點:
1.客戶端必須知道所有的策略類,區分他們之間的區別,並自行決定使用哪一個策略類。
2.針對每一種行為情況需要創建一個策略類,造成很多的策略類。
個人站點地址:www.mycookies.cn(適合java初學者的個人博客項目) github:https://github.com/liqianggh/blog
設計模式:HelloWorld之策略模式