还在使用 if else 写代码?试试 “策略模式” 吧!


Share{
public void shareOptions(String option){
if(option.equals("微博")){
//function1(); //... }else if(option.equals("微信")){
//function2(); //... }else if(option.equals("朋友圈")){
//function3(); //... }else if(option.equals("QQ")){
//function4(); //...}
//...}
如果只是写一个这么简单的功能,那么这样的代码也未尝不可,因为这样的代码量不多,后续也不需要怎么拓展和修改,维护起来也不算麻烦。但是,我们工作中遇到的都是一些比较复杂的项目,要保证项目的可读性、可维护性和可拓展性,就必须在代码上下功夫了。这里我们就要提到一个概念,那就是设计模式了。设计模式是指针对软件开发过程中重复发生的问题的解决办法。其中以被称为Gang of Four(GoF)的4人整理出的23种设计模式最为有名。当然,我不可能在这里把23种设计模式全部介绍完,就算全部介绍一遍,而且你还能全部记住,也不一定奏效。首先,你没有必要全部记下来,因为这23种设计模式并非都是经常使用到的设计模式。其次,死记硬背下这些设计模式没有任何意义,重要的是在自己脑海中理解设计模式是怎样解决问题的。今天我们就谈谈可以优化以上问题的设计模式,策略模式(Strategy Design Pattern)。策略模式(Strategy Design Pattern)
策略指的是计策、谋略,而模式一般指人为整理而成的,在某种场景下重复发生的问题的解决办法。在编程中,我们可以把策略看做是“算法”,而策略模式,按照GoF的定义,就是我们设计一些算法,把它们封装起来,让它们可以相互替换,这样就可以轻松地切换不同的算法来解决同一个问题。
我们看一下策略模式中有哪些角色。Strategy(策略)Strategy角色负责决定实现策略所必需的接口(API)。在示例程序中,由strategy接口扮演此角色。
ConcreteStrategy(具体的策略)ConcreteStrategy角色负责实现Strategy角色的接口(API),即负责实现具体的策略(战略、方向、方法和算法)。
Context(上下文)负责使用Strategy角色。Context角色保存了ConcreteStrategy角色的实例,并使用ConcreteStrategy角色去实现需求(总之,还是要调用Strategy角色的接口(API))。
再看看策略模式的类图:
{
void dealMythod(String option);
}
//定义具体的策略1public class DealSina implements DealStrategy{
@override public void dealMythod(String option){
//...}
}
//定义具体的策略2public class DealWeChat implements DealStrategy{
@override public void dealMythod(String option){
//...}
}
//定义上下文,负责使用DealStrategy角色public static class DealContext{
privateString type;
privateDealStrategy deal;
public DealContext(String type,DealStrategy deal){
this.type = type;
this.deal = deal;
}
public DealStrategy getDeal(){
returndeal;
}
public boolean options(String type){
return this.type.equals(type);
}
}
public voidShare{
private static List< DealContext> algs = newArrayList();
//静态代码块,先加载所有的策略static{
algs.add( newDealContext("Sina",newDealSina()));
algs.add( new DealContext("WeChat",newDealWeChat()));
}
public void shareOptions(String type){
DealStrategy dealStrategy = null;
for (DealContextdeal : algs) {
if(deal.options(type)) {
dealStrategy = deal.getDeal();
break;
}
}
dealStrategy.dealMythod(type);
}
}
再回忆一下策略模式中的各个角色,代码中的DealStrategy接口就是策略,DealSina和DealWeChat是具体的策略,DealContext就是使用策略的上下文。
所以这样的代码已经符合策略模式的代码结构了。我们通过策略模式将策略的定义、创建、使用解耦,让每一部分都不至于太复杂,也去除了if...else这样的条件判断语句,代码的可维护性和可拓展性都提高了。我们把可变的部分放到 了Share 类中的静态代码段中。如果有新的需求,要添加一个分享的方式时,只需要定义好具体的策略,然后修改 Share 类中的静态代码段,其他代码都不需要修改。策略模式还是比较常用的一种设计模式,比如java中给我定义好的Comparator 接口就是策略模式的一个实践。如果需要对某个类的排序,而该类没有实现Comparable接口,那么可以建立一个实现Comparator接口的比较器即可。通过实现Comparator类来新建一个比较器,然后通过该比较器来对类进行排序。//策略接口public interface Comparator<T>{
int compare(T o1, T o2);
}
//需要我们来定义具体的策略public class sorter implements Comparator{
public int compare(String s1, String s2){
returnInteger.compare(s1.length(), s2.length());
}
}
//一般我们会用更简洁的Lambda表达式来实现如果你使用的是Java ,想更符合开闭原则,并对反射有一定了解,那还可以通过反射来避免对类的修改。你可以通过一个配置文件或者定义一个注解来标注定义的策略类;通过读取配置文件或者搜索被标注的策略类,通过反射动态地加载这些策略类、创建策略对象;当我们新添加一个策略的时候,只需要将这个新添加的策略类添加到配置文件或者用定义的注解标注即可。Strategy模式特意将算法与其他部分分离开来,只是定义了与算法相关的接口(APl),然后在程序中以委托的方式来使用算法。这样看起来程序好像变复杂了,其实不然。例如,当我们想要通过改善算法来提高算法的处理速度时,如果使用了Strategy模式,就不必修改Strategy角色的接口(API)了,仅仅修改ConcreteStrategy角色即可。而且,使用委托这种弱关联关系可以很方便地整体替换算法。例如,使用Strategy模式编写棋类程序时,可以方便地根据棋手的选择切换AI电脑的水平。至此,我们可以小结出策略模式的使用场景:一个项目中有许多类,它们之间的区别仅在于它们的行为,希望动态地让一个对象在许多行为中选择一种行为时;
一个项目需要动态地在几种算法中选择一种时;
一个对象有很多的行为,不想使用多重的条件选择语句来选择使用哪个行为时。
策略模式不仅仅可以优化if else代码,其主要的作用还是解耦策略的定义、创建和使用,控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多。除此之外,对于复杂代码来说,策略模式还能让其满足开闭原则,添加新策略的时候,最小化、集中化代码改动,减少引入 bug 的风险。

扫一扫,关注我们