一、定义
策略模式的定义:策略模式就是将一系列算法封装起来,并使它们之间相互替换。被封装起来的算法具有独立性外部不可改变其特性。–《来源于网络》
二、解决的问题
解决代码中充斥大量if…else造成高耦合度和复杂度,增加代码维护成本。
三、UML结构示意图
四、实际应用
话说小编在入职一家新公司后,接到了一个代码维护的项目,需要面对一堆的祖传代码,其中有一个1000多行的类核心代码大概像下面这个样子:
if(condition1){
}else if(condition2){
}else if(condition3){
}else if(condition4){
}else{
}
每个分支中都有数十行甚至数百行代码,正常情况下小编是不会主动去调整祖传代码的,这里要遵从‘够用原则’,能跑就行。但是这部分代码以后需要我来维护,而且就在小编入职不久就修改了两次,因此,就决定进行优化。
再说一些关于优化代码的题外话。像小编这种情况各位朋友可能也遇到过,自己编写代码的时候也有过类似的情况,项目工期紧、项目初期业务简单,所以在编码的合理性上可能会有不妥的地方。首先,我没有觉得这有什么不妥,还是够用原则。但是在业务发生变化的时候,我们就要考虑优化原来编码中‘不妥’的地方,那么什么时候去优化呢?小编给出的建议是,当同一部分代码改动超过2次以上(再一再二不再三);再者就是,从项目初期就可预见的需要大量的条件判断,这个时候就不要偷懒了,一定要优化,否则都是给自己挖的坑。
下面开始进行代码优化,采用策略模式解决上面if…else。为了安全起见,首先将各个判断语句间的代码从各个分支中剥离出来,然后进行测试,看看输出是否有问题,剥离后的代码如下所示:
if(condition1){
doSomething1()
}else if(condition2){
doSomething2()
}else if(condition3){
doSomething3()
}else if(condition4){
doSomething4()
}else{
doOther()
}
doSomething1()
doSomething2()
doSomething3()
doSomething4()
doOther()
代码剥离后,就可以编写策略代码,并将各个方法迁移到各自的策略中。
首先,创建HandlerStrategy接口类
interface HandlerStrategy {
void doSomething();
}
编写3个实现类,Handler1、Handler2、Handler3
class Handler1 implements HandlerStrategy{
@Override
public void doSomething() {
System.out.println("Handler1--->doSomething");
}
}
class Handler2 implements HandlerStrategy{
@Override
public void doSomething() {
System.out.println("Handler2--->doSomething");
}
}
class Handler3 implements HandlerStrategy{
@Override
public void doSomething() {
System.out.println("Handler3--->doSomething");
}
}
编写策略工厂类
final class HandlerProvider {
private HandlerProvider() {
}
static HandlerStrategy getHandler(String type) {
if (type.equals("Handler1")) {
return new Handler1();
} else if (type.equals("Handler2")) {
return new Handler2();
} else if (type.equals("Handler3")) {
return new Handler3();
} else {
return null;
}
}
}
上面的代码完全可以实现功能,但是没有解决耦合的问题,只是将耦合点换了个地方,并且每增加一种策略都需要改动工厂类,不符合开闭原则。
继续优化,增加抽象工厂
public interface HandlerFactory {
HandlerStrategy createHandler();
}
分别为不同的handler创建各自的工厂
public class Handler1Factory implements HandlerFactory{
@Override
public HandlerStrategy createHandler() {
return new Handler1();
}
}
public class Handler2Factory implements HandlerFactory{
@Override
public HandlerStrategy createHandler() {
return new Handler3();
}
}
public class Handler3Factory implements HandlerFactory{
@Override
public HandlerStrategy createHandler() {
return new Handler3();
}
}
并将HandlerProvider修改为如下:
final class HandlerProvider {
private static Map<String,HandlerFactory> handlerFactorys = new HashMap<>(3);
static {
handlerFactorys.put("Handler1",new Handler1Factory());
handlerFactorys.put("Handler2",new Handler2Factory());
handlerFactorys.put("Handler3",new Handler3Factory());
}
private HandlerProvider() {
}
static HandlerStrategy getHandler(String type) {
return handlerFactorys.get(type).createHandler();
}
}
此时,我们可以看到已经将if…else优化掉了。但是,新增策略的时候,依然还是要改动
HandlerProvider,并且没增加一种策略都要对应增加抽象工厂,代码量相对较大,继续优化。
将创建handler的抽象工厂类删除,并将创建handler的工厂方法迁移至handler中,代码如下:
class Handler1 implements HandlerStrategy{
private Handler1(){}
static Handler1 getInstance(){
return new Handler1();
}
@Override
public void doSomething() {
System.out.println("Handler1--->doSomething");
}
}
class Handler2 implements HandlerStrategy{
private Handler2(){}
static Handler2 getInstance(){
return new Handler2();
}
@Override
public void doSomething() {
System.out.println("Handler2--->doSomething");
}
}
class Handler3 implements HandlerStrategy{
private Handler3(){}
static Handler3 getInstance(){
return new Handler3();
}
@Override
public void doSomething() {
System.out.println("Handler3--->doSomething");
}
}
创建枚举类,EHandler,用于保存handler类型间的关系,代码如下:
public enum EHandler {
Handler1Type(Handler1.getInstance()),
Handler2Type(Handler2.getInstance()),
Handler3Type(Handler3.getInstance());
private HandlerStrategy handlerStrategy;
public HandlerStrategy getHandlerStrategy(){
return this.handlerStrategy;
}
EHandler(HandlerStrategy handlerStrategy){
this.handlerStrategy = handlerStrategy;
}
}
创建HandlerHelper,用于对外调用使用,整个策略的包,只对外暴露HandlerHelper,调用者根本不需要知道包内部是如何实现的。
public final class HandlerHelper {
private HandlerHelper(){}
public static void doHandler(String type){
EHandler.valueOf(type).getHandlerStrategy().doSomething();
}
}
验证程序:
public class Main {
public static void main(String[] args) {
HandlerHelper.doHandler("Handler1Type");
HandlerHelper.doHandler("Handler2Type");
HandlerHelper.doHandler("Handler3Type");
}
}
运行结果:
Handler1--->doSomething
Handler2--->doSomething
Handler3--->doSomething
至此,完成了if…else的优化,不足的地方是新增handler的时候,还是需要维护枚举类。这个就要看具体的需求了,如果策略数量不是很多可以考虑采用这种方式;如果策略数量多,可以考虑采用反射。
五、复盘
ler2Type");
HandlerHelper.doHandler(“Handler3Type”);
}}
运行结果:
运行结果:
Handler1—>doSomething
Handler2—>doSomething
Handler3—>doSomething
至此,完成了if...else的优化,不足的地方是新增handler的时候,还是需要维护枚举类。这个就要看具体的需求了,如果策略数量不是很多可以考虑采用这种方式;如果策略数量多,可以考虑采用反射。
## 五、复盘
今天主要和大家分享策略模式,顺便分享了一下优化代码的一些心得,并且演练了一下优化if...else的过程。今天的分享就到这里,欢迎各位小伙伴留言,共同进步。