預先定義有著不同執行過程但結果相同的演演算法族,執行時指定所需演演算法。
演演算法族
此處為一組有共同主題的有相同結果的不同演演算法的集合。
話不多說,看個優化案例。
不使用策略模式的案例。四種不同的計算策略。使用者端的程式碼如下。
// 使用者端
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
條件判斷了,如下。
只需修改使用者端,其他程式碼不變。
// 使用者端
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
條件判斷,傳入什麼樣的物件就使用什麼物件的行為。
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
語句,而不設計物件建立的封裝與優化。
說到物件建立的優化,就得說到工廠模式了,事實上在使用策略模式時,為了建立物件也變得方便,通常也會使用到工廠模式進行優化。詳情看以下優化案例。
現有程式碼都不需要改變,只需要使用簡單工廠封裝上下文物件的建立即可。
// 工廠類,建立持有不同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
語句時。本文來自部落格園,作者:spoonb,轉載請註明原文連結:https://www.cnblogs.com/spoonb/p/16750785.html
個人主頁:blogcafe.cn 比部落格園更新速度更快,歡迎大家的光顧