簡述
預先定義有著不同執行程序但結果相同的演算法族,運行時指定所需演算法,
演算法族
此處為一組有共同主題的有相同結果的不同演算法的集合,
話不多說,看個優化案例,
優化案例
最初版v0
不使用策略模式的案例,四種不同的計算策略,客戶端的代碼如下,
// 客戶端
public class Client {
public static void main(String[] args) {
String target = "公園";
Scanner sc = new Scanner(System.in);
String input = sc.next();
if ("foot".equals(input)) {
System.out.println("徒步到目的地:" + target);
} else if ("bike".equals(input)) {
System.out.println("騎自行車到目的地:" + target);
} else if ("car".equals(input)) {
System.out.println("開車到目的地:" + target);
}
sc.close();
}
}
具體的條件分支都寫在客戶端,日后增加新的條件分支時也需要修改客戶端,修改客戶端這件事往往是不太愿意接受的,原因是我們希望客戶端盡可能少的改變,以便減少客戶使用系統的學習成本,
傳統的方法就只能增加if條件判斷了,如下,
修改版v1
只需修改客戶端,其他代碼不變,
// 客戶端
public class Client {
public static void main(String[] args) {
String target = "公園";
Scanner sc = new Scanner(System.in);
String input = sc.next();
if ("foot".equals(input)) {
Foot foot = new Foot();
foot.toTarget(target);
} else if ("bike".equals(input)) {
Bike bike = new Bike();
bike.toTarget(target);
} else if ("car".equals(input)) {
Car car = new Car();
car.toTarget(target);
}
sc.close();
}
}
可以看出客戶端依舊與各個具體的類耦合(從類的創建到方法的呼叫都是如此),
可以使用策略模式優化,使得方法呼叫不需要if條件判斷,傳入什么樣的物件就使用什么物件的行為,
修改版v2(策略模式)
public interface Trans {
void toTarget(String target);
}
// 徒步去目的地
public class Foot implements Trans {
@Override
public void toTarget(String target) {
System.out.println("徒步到目的地:" + target);
}
}
// 騎自行車去目的地
public class Bike implements Trans {
@Override
public void toTarget(String target) {
System.out.println("騎自行車到目的地:" + target);
}
}
// 開車去目的地
public class Car implements Trans {
@Override
public void toTarget(String target) {
System.out.println("開車到目的地:" + target);
}
}
// 背景關系類,根據客戶端業務的需求持有不同的計算物件
public class Context {
private Trans trans;
public Context(Trans trans) {
this.trans = trans;
}
// 更改持有的計算物件
public change(Trans trans) {
this.trans = trans;
}
// 實際呼叫持有的trans實作計算
public int toTarget(String target) {
return trans.toTarget(target);
}
}
修改后,客戶端代碼呼叫,
// 客戶端
public class Client {
public static void main(String[] args) {
String target = "公園";
Scanner sc = new Scanner(System.in);
String input = sc.next();
Context context = null;
if ("foot".equals(input)) {
context = new Context(new Foot());
} else if ("bike".equals(input)) {
context = new Context(new Bike());
} else if ("car".equals(input)) {
context = new Context(new Car());
}
System.out.println(context.toTarget(target));
sc.close();
}
}
代碼量確實有一定的減少,但是客戶端代碼從只與各個具體Trans類的實作類耦合到多耦合一個背景關系類,這樣想與我們的需求背道而馳啊,實際上,單純的策略模式就是如此,只負責減少方法呼叫的if陳述句,而不設計物件創建的封裝與優化,
說到物件創建的優化,就得說到工廠模式了,事實上在使用策略模式時,為了創建物件也變得方便,通常也會使用到工廠模式進行優化,詳情看以下優化案例,
修改版v3(策略+簡單工廠)
現有代碼都不需要改變,只需要使用簡單工廠封裝背景關系物件的創建即可,
// 工廠類,創建持有不同Trans物件的背景關系物件
public class Factory {
public static Context create(String input) {
if ("foot".equals(input)) {
return new Context(new Foot());
} else if ("bike".equals(input)) {
return new Context(new Bike());
} else if ("car".equals(input)) {
return new Context(new Car());
}
return null;
}
}
修改后,客戶端代碼呼叫,
// 客戶端
public class Client {
public static void main(String[] args) {
String target = "公園";
Scanner sc = new Scanner(System.in);
Context context = Factory.create(sc.next());
System.out.println(context.toTarget(target));
sc.close();
}
}
客戶端代碼大幅減少,并且客戶端中僅僅與Context類存在耦合,創建與使用的核心邏輯都從客戶端剝離,且具體呼叫的方法也只有在運行時才知曉(核心目的),這樣就能少些很多if陳述句了,
總結
優點
- 可以大幅減少if陳述句的書寫,
- 增加新的實作方法也不需要修改客戶端代碼,只需要增加實作類,
缺點
-
單純的策略模式需要客戶端對于各個實作類有足夠的了解,提升了開發時對系統的理解難度,
-
策略過多時,存在策略膨脹的問題,鑒于策略膨脹問題,應該慎用策略模式,這是使用混合模式或許可以解決這個問題,
混合模式
即在策略模式的實作類的方法中使用if陳述句分割各個情況,
適用場景
- 想要優化系統中過多的
if陳述句時,
本文來自博客園,作者:spoonb,轉載請注明原文鏈接:https://www.cnblogs.com/spoonb/p/16750785.html
個人主頁:blogcafe.cn 比博客園更新速度更快,歡迎大家的光顧
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/525924.html
標籤:其他
