第1章 引子:什麼是策略模式
1-1 策略模式簡介
- 什麼是策略模式
- 策略模式如何實現
- 策略模式總結篇
- 實際案例分享
日常生活中的例子:
- 文本編輯軟件–》佈局 –》佈局算法
- 算法實現1
- 算法實現2
- 算法實現3
- 購物–》支付–》支付算法
- 招商銀行
- 建設銀行
- XXX銀行
共同點:
- 抽象出不變部分
- 定義算法族分別封裝起來
- 客戶端不會受算法改變的影響
- 對新增需求彈性的支持
策略模式將可變的部分從程序中抽象分離成算法接口,在改接口下分別
封裝一系列算法實現並使他們可以相互替換,從而導致客戶端程序獨立
獨立於算法的改變。
第2章 光榮與夢想——鴨子應用:策略模式的實現
2-1 光榮與夢想:模擬應用背景介紹
光榮與夢想:鴨子應用
- 飛行的能力
- 更多類型的鴨子
每六個月發佈一款產品
鴨子的鳴叫
- 鴨子的顯示
- 原有的功能
- 飛行的能力
2-2 求索之路:鴨子如何才能飛
原有代碼
/*
* 超類,所有的鴨子都要繼承此類
* 抽象了鴨子的行爲:顯示和鳴叫
*/
public abstract class Duck {
/*
* 鴨子發出叫聲
* 通用行爲,由超類實現
*/
public void quack(){
System.out.println("嘎嘎嘎");
}
/*
* 顯示鴨子的外觀
* 鴨子的外觀各不相同,聲明爲abstract, 由子類實現
*/
public abstract void display();
}
public class MallardDuck extends Duck {
public MallardDuck(){
super();
}
@Override
public void display() {
System.out.println("我的脖子是綠色的");
}
}
public class RedheadDuck extends Duck {
public RedheadDuck(){
super();
}
@Override
public void display() {
System.out.println("我的頭是紅色的");
}
}
讓我們的鴨子飛起來
方案一:
在父類中提供實現方法,子類通過繼承獲得父類中的飛行行爲
public void fly(){
System.out.println("用翅膀飛行");
}
- 優點
- 簡(cu)單(bao)易(chou)用(lou),已有應用可以快速添加飛行的能力
- 缺點
- 不具有靈活性,對未來變更支持差。
- 需要通過在子類中覆寫飛行的方法以提供新的飛行行爲。這很容易造成錯誤(粗心的程序員忘記覆寫)。
方案二:抽象方法
在父類中提供抽象方法,強迫子類實現自己的飛行行爲
public abstract void fly();
- 優點
- 足夠靈活。
- 小夥伴再也不會忘記覆寫代碼了。
- 缺點
- 累死小夥伴了。
- 每個子類都要實現一遍代碼,及時是相同的行爲也不例外。
- 代碼重複,沒有複用代碼。
2-3 柳暗花明:策略讓鴨子飛上天
集成是重用代碼的利器
但繼承並不總是最好的工具
Favor composition over inheritace ———— Effective Java
複合優先與繼承
多用組合,少用繼承
面向對象 組合
Car has-a Tyre
汽車通過使用輪胎獲得輪胎的能力
在類中增加一個私有域,引用另一個已有的類的實例,通過調
用引用實例的方法從而獲得新的功能,這種設計被稱作組合(複合)。
方案三:組合
將飛行行爲抽象爲接口,在父類中持有該接口,並由該接口代理飛行行爲。
public interface FlyingStragety{
void performFly();
}
private FlyingStragety flyingStragety;
public void fly(){
flyingStragety.performFly();
}
- 優點
- 足夠靈活。
- 複用代碼,更易於維護。
- 缺點
- 見第三章總結中缺點
2-4 腳踏實地:用代碼放飛鴨子
/*
* 策略接口,實現鴨子的飛行行爲
*/
public interface FlyingStragety {
void performFly();
}
/*
* 超類,所有的鴨子都要繼承此類
* 抽象了鴨子的行爲:顯示和鳴叫
*/
public abstract class Duck {
/*
* 鴨子發出叫聲
* 通用行爲,由超類實現
*/
public void quack(){
System.out.println("嘎嘎嘎");
}
/*
* 顯示鴨子的外觀
* 鴨子的外觀各不相同,聲明爲abstract, 由子類實現
*/
public abstract void display();
private FlyingStragety flyingStragety;
public void setFlyingStragety(FlyingStragety flyingStragety) {
this.flyingStragety = flyingStragety;
}
public void fly(){
flyingStragety.performFly();
}
}
public class FlyWithWin implements FlyingStragety {
public void performFly() {
System.out.println("振翅高飛");
}
}
public class MallardDuck extends Duck {
public MallardDuck(){
super();
super.setFlyingStragety(new FlyWithWin());
}
@Override
public void display() {
System.out.println("我的脖子是綠色的");
}
}
public class RedheadDuck extends Duck {
public RedheadDuck(){
super();
super.setFlyingStragety(new FlyWithWin());
}
@Override
public void display() {
System.out.println("我的頭是紅色的");
}
}
public class DuckTest {
public static void main(String[] args){
System.out.println("測試鴨子程序");
System.out.println("************************");
Duck duck = null;
// duck = new MallardDuck();
duck = new RedheadDuck();
duck.display();
duck.quack();
duck.fly();
System.out.println("************************");
System.out.println("測試完畢");
}
}
2-5 擁抱變化:用策略模式提供高複用性代碼
新加兩款產品,不能飛行
public class FlyNoWay implements FlyingStragety {
public void performFly() {
System.out.println("我不會飛行!");
}
}
public class RubberDuck extends Duck {
public RubberDuck() {
super();
super.setFlyingStragety(new FlyNoWay());
}
@Override
public void display() {
System.out.println("我全身發黃,嘴巴很紅");
}
public void quack(){
System.out.println("嘎~嘎~嘎~");
}
}
public class BigYellow extends Duck {
public BigYellow() {
super();
super.setFlyingStragety(new FlyNoWay());
}
@Override
public void display() {
System.out.println("我身體很大,全身黃黃");
}
}
2-6 萬變不離其宗:向宇宙進軍
新增太空鴨
public class FlyWithRocket implements FlyingStragety {
public void performFly() {
System.out.println("用火箭在太空遨遊");
}
}
public class SpaceDuck extends Duck {
public SpaceDuck() {
super();
super.setFlyingStragety(new FlyWithRocket());
}
@Override
public void display() {
System.out.println("我頭戴宇航頭盔");
}
public void quack(){
System.out.println("我通過無線電與你通信");
}
}
橡膠鴨、大黃鴨
- 代碼複用
太空鴨
- 更換策略模式
一生二,二生三,三生無窮!
第3章 總結篇
3-1 知識點總結
策略模式中的設計原則
- 找出應用中需要變化的部分,把他們獨立出來,不要和那些不需要變化的代碼混在一起。
- 面向接口編程,而不是面向實現編程。
- 多用組合,少用繼承。
策略模式的實現
- 通過分離變化得出的策略接口Strategy
- Strategy的實現類
- 客戶程序“有一個”Strategy
- 在客戶程序中選擇/組裝正確的Strategy實現
策略模式的優點
- 使用了組合,使架構更加靈活
- 富有彈性,可以較好的應對變化(開—閉原則)
- 更好的代碼複用性(相對於繼承)
- 消除大量的條件語句
策略模式的缺點
- 客戶代碼需要了解每個策略實現的細節
- 增加了對象的數目
策略模式的適用場景
- 許多相關的類僅僅是行爲差異
- 運行時選取不同的算法變體
- 通過條件語句在多個分支中選取一