需求
某市公交公司要求做一个公交收费系统,针对不同公交方式采取不同收费算法。
解决方案
解决方案 V1.0
客户端 Client类
public class Client {
public static void main(String[] args){
PublicChargeAPI api = new PublicChargeAPI();
api.calculatePriceOfBus(10);
api.calculatePriceOfMetro(20);
}
}
公交系统收费计算API PublicChargeAPI
public class PublicChargeAPI {
public int calculatePriceOfBus(int distance){
// 此处省略计算巴士价格代码
return 0;
}
public int calculatePriceOfMetro(int distance){
// 此处省略计算地铁价格代码
return 0;
}
}
方案缺点 没有统一的收费计算入口,无法做到共用逻辑的控制
改进方案 V1.1
客户端 Client类
public class Client {
public static void main(String[] args){
PublicChargeAPI api = new PublicChargeAPI();
api.calculatePrice(10, PublicChargeAPI.BUS);
api.calculatePrice(20, PublicChargeAPI.METRO);
}
}
公交系统收费计算API PublicChargeAPI
public class PublicChargeAPI {
public static final int BUS = 1;
public static final int METRO = 2;
public int calculatePrice(int distance, int type){
if (type == BUS){
return calculatePriceOfBus(distance);
} else if (type == METRO){
return calculatePriceOfMetro(distance);
}
return -1;
}
private int calculatePriceOfBus(int distance){
// 此处省略计算巴士价格代码
return 0;
}
private int calculatePriceOfMetro(int distance){
// 此处省略计算地铁价格代码
return 0;
}
}
方案缺点 所有收费方式写在一个类里面,紧耦合,不符合单一职责原则。
改进方案 V1.2
客户端 Client类
同上
公交系统收费计算API PublicChargeAPI
public class PublicChargeAPI {
public static final int BUS = 1;
public static final int METRO = 2;
public int calculatePrice(int distance, int type){
if (type == BUS){
BusCharge bc = new BusCharge();
return bc.calculate(distance);
} else if (type == METRO){
MetroCharge mc = new MetroCharge();
return mc.calculate(distance);
}
return -1;
}
}
巴士收费方式类 BusCharge
public class BusCharge {
public int calculate(int distance){
// 此处省略计算巴士价格代码
return 0;
}
}
地铁收费方式类 MetroCharge
public class MetroCharge {
public int calculate(int distance){
// 此处省略计算地铁价格代码
return 0;
}
}
方案缺点
| 每次增加一种收费方式不仅要新添一个收费类,还要修改“PublicChargeAPI”类的“calculatePrice”方法,在其中新增一个“else”分支,这不符合“开闭原则”。之所以会这样是因为客户端“Client”类只做了一次“模糊选择”,选择了“1”或“2”等,并没有明确指明要用哪个收费类,所以在“PublicChargeAPI”类中必须根据“1”或“2”等来选择具体用哪个收费类 |
改进方案 V2.0(策略模式)
客户端 Client类
public class Client {
public static void main(String[] args){
PublicChargeAPI api = new PublicChargeAPI();
api.setPublicChargeStrategy(new ImplBusCharge());
api.calculatePrice(10);
api.setPublicChargeStrategy(new ImplMetroCharge());
api.calculatePrice(20);
}
}
公交系统价格计算API PublicChargeAPI
public class PublicChargeAPI {
IPublicCharge mChargeStrategy;
public void setPublicChargeStrategy(IPublicCharge chargeStrategy){
mChargeStrategy = chargeStrategy;
}
public int calculatePrice(int distance){
return mChargeStrategy.calculate(distance);
}
}
抽象收费接口 IPublicCharge
public interface IPublicCharge {
int calculate(int distance);
}
巴士收费具体类 ImplBusCharge
public class ImplBusCharge implements IPublicCharge {
@Override
public int calculate(int distance) {
// 此处省略计算巴士价格代码
return 0;
}
}
地铁收费具体类 ImplMetroCharge
public class ImplMetroCharge implements IPublicCharge {
@Override
public int calculate(int distance) {
// 此处省略计算地铁价格代码
return 0;
}
}
方案缺点
| 此种方案也有缺点,相较于其他方案“Client”类除了需要认识“PublicChargeAPI”类还要认识“IPublicCharge”、“ImplBusCharge”、“ImplMetroCharge”等,这不符合“迪米特法则”(最少知识原则,一个对象要尽可能少的引用其他对象)。 |
总结
在调用同一个接口时如果有可能发生算法替换推荐使用策略模式,没有完美的设计模式。