状态机设计模式和策略模式 (设计模式解析策略模式完整代码)

背景

策略模式是一种比较简单的设计模式,生活中做成一件事有几种不同的策略选择供你达成。比如你上班可以选择坐公交上班,可以选择坐地铁上班,也可以选择自驾上班,甚至还可以步行上班。

如果需要用代码表示上面的内容,你可以使用多重条件语句实现。

if("1".equals(status)){
return"公交";
}elseif("2".equals(status)){
return"地铁";
}elseif("3".equals(status)){
return"自驾";
}elseif("4".equals(status)){
return"步行";
}

但是上面这样的代码实际就是硬编码,如果需要增加、移除、修改算法,需要在这里修改,违反了开闭原则。这个问题可以使用策略模式解决。

如果使用if语句,大概是这样的一个流程图:

策略设计模式与状态设计模式,责任链设计模式和策略模式

if语句

使用策略模式的流程图:

策略设计模式与状态设计模式,责任链设计模式和策略模式

策略模式

什么是策略模式

Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。)

将算法调用方与算法实现方分割开来,实现两者之间的解耦。

策略模式的主要组成要素如下:

抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。环境(Context)类:持有一个策略类的引用,最终给客户端调用。

代码实现

How2WorkStrategy

抽象策略类

interfaceHow2WorkStrategy{
Stringhow2WorkFun();
}

SubwayStrategy

地铁策略类

publicclassSubwayStrategyimplementsHow2WorkStrategy{
@Override
publicStringhow2WorkFun(){
return"地铁";
}
}

CarStrategy

自驾小车策略类

publicclassCarStrategyimplementsHow2WorkStrategy{
@Override
publicStringhow2WorkFun(){
return"自驾";
}
}

BusStrategy

公交车策略类

publicclassBusStrategyimplementsHow2WorkStrategy{
@Override
publicStringhow2WorkFun(){
return"公交";
}
}

WalkStrategy

步行策略类

publicclassWalkStrategyimplementsHow2WorkStrategy{
@Override
publicStringhow2WorkFun(){
return"步行";
}
}

Context

装载类,可理解为策略工厂。

publicclassContext{
publicHow2WorkStrategygetHow2WorkStrategy(){
returnhow2WorkStrategy;
}

publicvoidsetHow2WorkStrategy(How2WorkStrategyhow2WorkStrategy){
this.how2WorkStrategy=how2WorkStrategy;
}

privateHow2WorkStrategyhow2WorkStrategy;

publicStringhow2Work(){
returnhow2WorkStrategy.how2WorkFun();
}

}

测试代码:

@org.junit.Test
publicvoidtest(){
Contextcontext=newContext();
How2WorkStrategyhow2WorkStrategy=newCarStrategy();
context.setHow2WorkStrategy(how2WorkStrategy);
Strings=context.how2Work();
Console.log(s);
Console.log("---------------------");
how2WorkStrategy=newBusStrategy();
context.setHow2WorkStrategy(how2WorkStrategy);
Strings1=context.how2Work();
Console.log(s1);
}

我们选择自驾策略和公交车策略,测试结果如下:

自驾
---------------------
公交

上面代码还有缺陷,上层模块必须知道有哪些策略,然后才能决定使用哪一个策略,这与迪米特法则是相违背的,我只是想使用了一个策略,我凭什么就要了解这个策略呢?那要你的封装类还有什么意义?这是原装策略模式的一个缺点,幸运的是,我们可以使用其他模式来修正这个缺陷,如工厂方法模式、代理模式或享元模式。

关于改进方法,有兴趣的还可以看看我的这篇文章:

if-else语句太多了?我用设计模式消除了if-else

关于策略模式的思考

策略模式比较简单,如果存在多重if语句。并且if语句还有可能变化,那么我们就可以将if语句中的算法封装到类中,使用策略模式代替if语句。

总之策略模式就是:算法可自由切换、避免多重if-else语句、更好的扩展性。