策略模式 java-23种设计模式的策略模式,你会如何实现?
我们使用的app大多都有分享的功能,我们可以选择不同的地方,比如微博、微信、QQ等等,虽然是同一个内容,但是不同的平台就会有不同的处理方式,比如要跳转到不同的app或者直接复制链接等等。如果让你来实现这个功能,你会如何实现呢?
如果你对设计模式不熟悉,那么第一反应就是有if...else或者switch语句来进行条件判断,根据用户的不同选择而使用不同的处理方法。我们用代码简化地处理一下:
public void 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种设计模式全部介绍完,就算全部介绍一遍策略模式 java,而且你还能全部记住,也不一定奏效。首先,你没有必要全部记下来,因为这23种设计模式并非都是经常使用到的设计模式。其次,死记硬背下这些设计模式没有任何意义,重要的是在自己脑海中理解设计模式是怎样解决问题的。
今天我们就谈谈可以优化以上问题的设计模式,策略模式(Strategy Design Pattern)。
策略模式(Strategy Design Pattern)
策略指的是计策、谋略,而模式一般指人为整理而成的,在某种场景下重复发生的问题的解决办法。在编程中,我们可以把策略看做是“算法”,而策略模式,按照GoF的定义,就是我们设计一些算法,把它们封装起来,让它们可以相互替换,这样就可以轻松地切换不同的算法来解决同一个问题。
我们看一下策略模式中有哪些角色。
再看看策略模式的类图:
介绍到这里,相信你对策略模式有了初步的认识,那我们就用策略模式来重构前面的代码,让你加深对策略模式的理解。
//定义策略接口
public interface DealStrategy{
void dealMythod(String option);
}
//定义具体的策略1
public class DealSina implements DealStrategy{
@override
public void dealMythod(String option){
//...
}
}
//定义具体的策略2
public class DealWeChat implements DealStrategy{
@override
public void dealMythod(String option){
//...
}
}
//定义上下文,负责使用DealStrategy角色
public static class DealContext{
private String type;
private DealStrategy deal;
public DealContext(String type,DealStrategy deal){
this.type = type;
this.deal = deal;
}
public DealStrategy getDeal{
return deal;
}
public boolean options(String type){
return this.type.equals(type);
}
}
public void Share{
private static Listalgs = new ArrayList;
//静态代码块,先加载所有的策略
static {
algs.add(new DealContext("Sina",new DealSina));
algs.add(new DealContext("WeChat",new DealWeChat));
}
public void shareOptions(String type){
DealStrategy dealStrategy = ;
for (DealContext deal : 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{
int compare(T o1, T o2);
}
//需要我们来定义具体的策略
public class sorter implements Comparator{
public int compare(String s1, String s2) {
return Integer.compare(s1.length, s2.length);
}
}
//一般我们会用更简洁的Lambda表达式来实现
如果你使用的是Java ,想更符合开闭原则,并对反射有一定了解,那还可以通过反射来避免对类的修改。
你可以通过一个配置文件或者定义一个注解来标注定义的策略类;通过读取配置文件或者搜索被标注的策略类,通过反射动态地加载这些策略类、创建策略对象;当我们新添加一个策略的时候,只需要将这个新添加的策略类添加到配置文件或者用定义的注解标注即可。
Strategy模式特意将算法与其他部分分离开来,只是定义了与算法相关的接口(APl),然后在程序中以委托的方式来使用算法。
这样看起来程序好像变复杂了,其实不然。例如,当我们想要通过改善算法来提高算法的处理速度时,如果使用了Strategy模式,就不必修改Strategy角色的接口(API)了,仅仅修改ConcreteStrategy角色即可。
而且,使用委托这种弱关联关系可以很方便地整体替换算法。例如,使用Strategy模式编写棋类程序时,可以方便地根据棋手的选择切换AI电脑的水平。
至此,我们可以小结出策略模式的使用场景:
策略模式不仅仅可以优化if else代码,其主要的作用还是解耦策略的定义、创建和使用,控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多。除此之外,对于复杂代码来说,策略模式还能让其满足开闭原则,添加新策略的时候,最小化、集中化代码改动,减少引入 bug 的风险。
可能有人会问:状态模式也可以优化if else,那么策略模式和状态模式又有什么不同呢?
让我们来简单回顾一下状态模式的类图:
使用策略模式和状态模式都可以替换被委托对象,而且它们的类之间的关系也很相似。但是两种模式的目的不同。
在策略模式中,ConcreteStrategy角色是表示算法的类。在Strategy模式中策略模式 java,可以替换被委托对象的类。当然如果没有必要,也可以不替换。
而在状态模式中,ConcreteState角色是表示“状态”的类。在State模式中,每次状态变化时,被委托对象的类都必定会被替换。
好了,关于策略模式我们就是介绍到这里。你在做项目时用过策略模式吗?是在什么场景中使用呢?欢迎留言说说。
PS:
最近,我的好朋友安老师开了一个”开启副业“的训练营,我给大家要了一些福利,对副业感兴趣的朋友,可以截图本文发给微信(a32352937)他会你少300元钱!
安老师是《副业赚钱之道》书籍的作者,同时也是一名自由职业,曾经在知乎上的一篇 Live 就赚了一台特斯拉,这两年一直在研究关于副业的相关内容,算是这方面的专家了,感兴趣的朋友可以扫码了解下。