定義
策略模式屬於對象的行爲模式。其用意是針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們可以相互替換。策略模式使得算法可以在不影響客戶端的情況下發生變化。
UML圖
- 環境(Context)角色:持有一個Strategy的引用,最終給客戶端調用。
- 抽象策略(Strategy)角色:這是一個抽象角色,通常由一個接口或抽象類實現。此角色給出所有的具體策略類所需的接口。
- 具體策略(ConcreteStrategy)角色:包裝了相關的算法或行爲。
實例
假設我們現在需要一個圖片加載框架,我們可以選擇Glide、Fresco、ImageLoader、Picasso其中的一個,比如選擇ImageLoader實現了圖片加載,正當我們美滋滋地實現了這個功能的時候,突然有一天Boss讓你把加載框架換成Glide,如果很多類都去調用了ImageLoader,那麼就得一個一個地去替換,替換到懷疑人生,如果之前使用到策略模式,那麼替換過程將會變得非常簡單。
首先來定義相應的角色:
1、環境角色:
public class Context {
Strategy strategy;
private Context() {
//在這裏切換讓誰去加載圖片
// strategy = new GlideStrategy();
// strategy = new PicassoStrategy();
// strategy = new FrescoStrategy();
strategy = new ImageLoaderStrategy();
}
public void loadImage() {
strategy.showImage();
}
public static Context getInstance() {
return InnerClass.context;
}
private static final class InnerClass {
private static Context context = new Context();
}
}
2、抽象策略角色
public interface Strategy {
void showImage();
}
3、具體策略角色
//Glide
public class GlideStrategy implements Strategy{
@Override
public void showImage() {
System.out.println("Glide ShowImage");
}
}
//Fresco
public class FrescoStrategy implements Strategy {
@Override
public void showImage() {
System.out.println("Fresco ShowImage");
}
}
//ImageLoader
public class ImageLoaderStrategy implements Strategy {
@Override
public void showImage() {
System.out.println("ImageLoader ShowImage");
}
}
//Picasso
public class PicassoStrategy implements Strategy {
@Override
public void showImage() {
System.out.println("Picasso ShowImage");
}
}
最後可以直接這麼調用:
Context.getInstance().loadImage();
這樣我們在Context的構造函數中初始化的哪個策略角色就會調用它的方法去加載圖片,從而讓圖片加載框架獨立於調用者而靈活變化。
完整代碼地址:策略模式
策略模式的優缺點
1、優點
- 對客戶隱藏具體策略(算法)的實現細節,彼此完全獨立。具體策略類實現自同一個接口,他們之間可以自由切換
- 易於擴展,如果需要添加新的策略類,基本不用改變現有代碼
- 使用策略模式可以避免使用多重條件轉移語句。多重轉移語句不易維護,它把採取哪一種算法或採取哪一種行爲的邏輯與算法或行爲的邏輯混合在一起,統統列在一個多重轉移語句裏面,比使用繼承的辦法還要原始和落後。
2、缺點
- 維護各個策略類會給帶來額外開銷,策略類太多時,消耗更大。
- 客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味着客戶端必須知道這些算法的區別並決定使用哪個策略類。
適用場景
- 幾個類的主要邏輯相同,只在部分邏輯的算法和行爲上稍有區別的情況。
- 有幾種相似的行爲,或者說算法,客戶端需要動態地決定使用哪一種,那麼可以使用策略模式,將這些算法封裝起來供客戶端調用。