小白設計模式:策略模式

CodeInfo發表於2018-12-23

定義

策略模式(Strategy),是一種物件行為模式:定義一系列的演算法,將可變的部分封裝起來,使得它們可以相互替換,讓變化的部分於獨立呼叫它的客戶而變化,不會導致呼叫方需要跟著修改。 (這邊的"演算法"指的是系統中經常會變的部分,可能是超類定義的行為,或者特徵之類的)

主要組成

抽象策略介面(Strategy): 定義同一組演算法的公共介面;

具體策略實現(Concrete Strategy): 實現具體的某種演算法;

客戶端(Client): 呼叫者,一般會有策略列表存放各種策略,根據需要選擇不同的策略實現功能;

UML圖

小白設計模式:策略模式

框架程式碼

Strategy:

public interface Strategy {
    void AlgorithmInterface();
}
複製程式碼

Concrete Strategy:

public class ConcreteStrategyA {
    @Override
    public void AlgorithmInterface(){
        //策略A的行為   
    }
}

public class ConcreteStrategyB {
    @Override
    public void AlgorithmInterface(){
        //策略B的行為   
    }
}
複製程式碼

Client:

Strategy strategy = new ConcreteStrategyA();
//Strategy strategy = new ConcreteStrategyB();
//執行處不管理策略具體實現細節
strategy.AlgorithmInterface();
複製程式碼

具體例子

UML圖

小白設計模式:策略模式

程式碼

Vehicle(Strategy策略模組):

/**
 * 交通工具
 *
 */
public interface Vehicle {
	//使用指定交通工具出發,不關心該工具的操作細節
	String go();
}
複製程式碼

Car:

public class Car implements Vehicle{

	@Override
	public String go() {
		return "開小汽車前往目的地";	
	}

}
複製程式碼

Bilk:

public class Bilk implements Vehicle{

	@Override
	public String go() {
		return "騎自行車前往目的地";
	}
}
複製程式碼

Plane:

public class Plane implements Vehicle{

	@Override
	public String go() {
		return "乘坐飛機前往目的地";
	}
}
複製程式碼

PayMent(Strategy策略模組):

/**
 * 支付方式
 *
 */
public interface PayMent {
	//不關心支付方式的操作流程,只關心付款結果
	String cost();
}
複製程式碼

AliPay:

public class AliPay implements PayMent{

	@Override
	public String cost() {
		return "使用支付寶流程付款";
	}
}
複製程式碼

WeChat:

public class WeChat implements PayMent{

	@Override
	public String cost() {
		return "使用微信流程付款";	
	}
}
複製程式碼

Crash:

public class Crash implements PayMent{

	@Override
	public String cost() {
		return "使用現金流程付款";
	}
}
複製程式碼

穩定部分TravelPlan(使用各種策略的地方): TravelPlan:

public abstract class TravelPlan {
    //可變的策略模組
	Vehicle vehicle;
	PayMent payMent;
	//公共穩定的操作介面
	public void setVehicle(Vehicle vehicle) {
		this.vehicle = vehicle;
	}
	
	public void setPayMent(PayMent payMent) {
		this.payMent = payMent;
	}
	
	public void go() {
		System.out.println((getGoTime() + payMent.cost() + vehicle.go() + getDestination()));
	}
	
	public abstract String getDestination();
	public abstract String getGoTime();
}
複製程式碼

BeijingTravelPlan:

public class BeijingTravelPlan extends TravelPlan{

	@Override
	public String getDestination() {
		return "北京";
	}

	@Override
	public String getGoTime() {
		return "2018.11.12.09:00";
	}
}
複製程式碼

TaiWanTravelPlan:

public class TaiWanTravelPlan extends TravelPlan{

	@Override
	public String getDestination() {
		return "臺灣";
	}

	@Override
	public String getGoTime() {
		return "2018.11.13.10:00";
	}
}
複製程式碼

簡單使用:

//定義北京旅遊計劃
	TravelPlan travelPlan = new BeijingTravelPlan();
	travelPlan.setPayMent(new WeChat());
	travelPlan.setVehicle(new Car());
	travelPlan.go();
	//告白出行交通工具和付款方式
	travelPlan.setPayMent(new Crash());
	travelPlan.setVehicle(new Bilk());
	travelPlan.go();
	
	日誌輸出:
	2018.11.12.09:00使用微信流程付款開小汽車前往目的地北京
    2018.11.12.09:00使用現金流程付款騎自行車前往目的地北京
複製程式碼

假設不使用策略模式

未將可變部分獨立出來,即不存在Vehicle和PayMent這2個演算法模組,則對於TravePlane繼承體系可能為:

小白設計模式:策略模式

public abstract class TravelPlan {
	String vehicleType;
	String payMentType;
	
	public void setVehicle(String vehicle) {
		this.vehicleType = vehicle;
	}
	
	public void setPayMent(String payMent) {
		this.payMentType = payMent;
	}
	
	public void go() {
		System.out.println((getGoTime() + payMentCost() + vehicleGo() + getDestination()));
	}
	
	//存在一大堆條件判斷
	public String vehicleGo () {
		switch (vehicleType) {
			case "Car":
				return "開小汽車前往目的地";	
			case "Bilk":
				return "騎自行車前往目的地";	
			case "Plane":
				return "乘坐飛機前往目的地";	
			default:
				return null;
		}
	}
	
	//存在一大堆條件判斷
	public String payMentCost () {
		switch (vehicleType) {
			case "AliPay":
				return "使用支付寶流程付款";	
			case "WeChat":
				return "使用微信流程付款";	
			case "Crash":
				return "使用現金流程付款";	
			default:
				return null;
		}
	}
	
	public abstract String getDestination();
	public abstract String getGoTime();

}
複製程式碼

經常會因為業務而發生修改擴充套件的部分都堆在了相對穩定的部分,沒有面向介面通過組合的方式,後續修改vehicle和PayMent部分可能會不經意點影響到了其它功能點。

總結

優點

1.策略模式封裝了可變部分,使得"可變"部分獨立於"穩定"部分,在經常性的增加修改"可變"部分過程不需要動到"穩定"部分,可用於取代將全部行為封裝到超類然後由每個子類都實現一遍的純繼承方式;

2.當演算法種類多的時候,避免了一系列的條件判斷,程式碼更簡潔;

3.不同演算法實現同一介面,可以互相替換,不需要硬編碼到呼叫處;

4.2者分離後可以去除在各個子類單獨實現演算法的重複部分;

缺點

  1. 比起將"可變"與"穩定"部分都放一起來講,類數目會增加比較多(大部分設計模式都會這樣)

應用場景

  1. 許多相同的類,但是僅僅是行為不一致,就可以使用策略模式,將不同的行為抽象介面,實現成各個行為演算法類;
  2. 單個類中,存在許多行為,但是在某些呼叫的地方需要使用if來判斷不同的行為,則可以將這些行為用策略模式優化;

微信公眾號

小白設計模式:策略模式

相關文章