作者 | LA

来源 | 程序员小灰(ID:chengxuyuanxiaohui)

我们使用的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种设计模式全部介绍完,就算全部介绍一遍,而且你还能全部记住,也不一定奏效。首先,你没有必要全部记下来,因为这23种设计模式并非都是经常使用到的设计模式。其次,死记硬背下这些设计模式没有任何意义,重要的是在自己脑海中理解设计模式是怎样解决问题的。

今天我们就谈谈可以优化以上问题的设计模式,策略模式(Strategy Design Pattern)。

策略模式

策略指的是计策、谋略,而模式一般指人为整理而成的,在某种场景下重复发生的问题的解决办法。在编程中,我们可以把策略看做是“算法”,而策略模式,按照GoF的定义,就是我们设计一些算法,把它们封装起来,让它们可以相互替换,这样就可以轻松地切换不同的算法来解决同一个问题。

我们看一下策略模式中有哪些角色。

  • Strategy(策略)Strategy角色负责决定实现策略所必需的接口(API)。在示例程序中,由strategy接口扮演此角色。

  • ConcreteStrategy(具体的策略)ConcreteStrategy角色负责实现Strategy角色的接口(API),即负责实现具体的策略(战略、方向、方法和算法)。

  • Context(上下文)负责使用Strategy角色。Context角色保存了ConcreteStrategy角色的实例,并使用ConcreteStrategy角色去实现需求(总之,还是要调用Strategy角色的接口(API))。

再看看策略模式的类图:

介绍到这里,相信你对策略模式有了初步的认识,那我们就用策略模式来重构前面的代码,让你加深对策略模式的理解。

//定义策略接口
public interface DealStrategy{void dealMythod(String option);
}//定义具体的策略1
public class DealSina implements DealStrategy{@overridepublic void dealMythod(String option){//...}
}//定义具体的策略2
public class DealWeChat implements DealStrategy{@overridepublic 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 List<DealContext> algs = new ArrayList();//静态代码块,先加载所有的策略static {algs.add(new DealContext("Sina",new DealSina()));algs.add(new DealContext("WeChat",new DealWeChat()));}
public void shareOptions(String type){DealStrategy dealStrategy = null;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<T> {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模式中,可以替换被委托对象的类。当然如果没有必要,也可以不替换。

而在状态模式中,ConcreteState角色是表示“状态”的类。在State模式中,每次状态变化时,被委托对象的类都必定会被替换。

好了,关于策略模式我们就是介绍到这里。你在做项目时用过策略模式吗?是在什么场景中使用呢?欢迎留言说说。

更多精彩推荐
☞挑战王者荣耀“绝悟” AI,会进化的职业选手太恐怖了!
☞一个月面试近 20 家,拿下阿里 Offer!
☞视频 | 你不知道的"开源"60年秘史
☞GitHub标星10,000+,Apache项目ShardingSphere的开源之路
☞阿里技术专家告诉你,如何画出优秀的架构图?
☞加拿大API平台如何做到30%为中国明星项目?创业老兵这样说……
你点的每个“在看”,我都认真当成了喜欢

还在用 if else?试试策略模式吧!相关推荐

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

    我们使用的app大多都有分享的功能,我们可以选择分享到不同的地方,比如微博.微信.QQ等等,虽然是同一个内容,但是分享到不同的平台就会有不同的处理方式,比如要跳转到不同的app或者直接复制链接等等.如 ...

  2. 别在再满屏的 if、else 了,试试策略模式,真香!!

    你还在写满屏的 if/ else/ switch 之类的判断逻辑吗? 栈长在开发人员的代码中看过太多这样的低级代码了,真的太 low,极不好维护,本文栈长就教你如何用策略模式干掉 if/ else/ ...

  3. 新来的“大神”用策略模式把if else给“优化”了,技术总监说:能不能想好了再改?

    我想大家肯定都或多或少的看过各种"策略模式"的讲解.布道等等,这篇文章就是来好好"澄清"一下策略模式,并尝试回答以下的问题: 策略模式是如何优化业务逻辑代码结构 ...

  4. 新来的大神用策略模式把if else给优化了,技术总监说:能不能想好了再改?...

    △Hollis, 一个对Coding有着独特追求的人△ 这是Hollis的第 285 篇原创分享 作者 l 上帝爱吃苹果 来源 l Hollis(ID:hollischuang) 本文来自作者投稿,原 ...

  5. [转]新来的大神用策略模式把if else给优化了,技术总监说:能不能想好了再改?...

    本文来自作者投稿,原作者:上帝爱吃苹果 目前在魔都,贝壳找房是我的雇主,平时关注一些 java 领域相关的技术,希望你们能在这篇文章中找到些有用的东西.个人水平有限,如果文章有错误还请指出,在留言区一 ...

  6. 避免过多if - else的新姿势:策略模式、工厂 + 策略

    目录 前言 需求 编码实现 思考 策略模式 什么是策略模式? 编码 深思 工厂 + 策略 toMap 效果 后续 前言 避免过多if - else的新姿势:卫语句.小函数.多态.反射 在之前文章说到, ...

  7. 还在if-else行走天下?试试【策略模式】吧

    什么是策略模式 首先策略模式属于GOF23中设计模式中的一种,是一种行为型的设计模式."行为"主要是指不同的方法或者算法. 其实就是我们定义和封装一些策略(或者说是算法),这些策略 ...

  8. 趣谈设计模式 | 策略模式(Strategy):你还在使用冗长的if-else吗?

    文章目录 案例:指挥官AI 策略模式 配合工厂模式 总结 完整代码与文档 案例:指挥官AI 案例可能不符合实际逻辑,仅用于表述设计模式的思想,勿介意 假设我们开发了一款类似全面战争的即时战略游戏,为了 ...

  9. c++switch实现猜拳_策略模式+简单工厂+注解消除 if-else/switch-case

    消除代码中的 if-else/switch-case 在很多时候,我们代码中会有很多分支,而且分支下面的代码又有一些复杂的逻辑,相信很多人都喜欢用 if-else/switch-case 去实现.做的 ...

最新文章

  1. 名词解释_写字楼租赁相关名词解释
  2. 信号源的ALC环路介绍
  3. validate做前端表单验证
  4. python3 拼接字符串的7种方法
  5. HazelCast的Spring-Boot和Cache抽象
  6. js中立即执行函数会预编译吗_作为前端你了解JavaScript运行机制吗?
  7. 基于DPDK+VPP实现高性能防火墙
  8. 数据上报java_通过Jaeger上报Java应用数据
  9. 激活函数、损失函数及其优化方法总结
  10. 【自用】图像算法、计算机视觉面试问题及答案1.0
  11. chattr -i authorized_keys 无效
  12. Android耗电原理及飞书耗电治理
  13. 文件上传事件兼容性解决方案:兼容ie和谷歌
  14. qt android 浮动窗口,QT+ 状态栏+核心控件+浮动窗口
  15. android 高光动画,记一个头像高光动画的CSS实现
  16. 架构师,你需要了解的git知识都在这里了
  17. 服务器操作系统不能显示全屏,服务器窗口显示不全屏
  18. 为什么我加了过滤器然后就登不进去了_化隆空气过滤器滤芯哪里有
  19. android画机器人,cdr怎么绘制安卓小人?cdr安卓机器人制作教程
  20. 【opencv450-samples】flann_search_dataset.cpp在数据集中搜索查询图片 说明 FLANN 使用的简单程序

热门文章

  1. web前端页面优化——个人见解
  2. Spring配置 context:component-scan/ mvc:annotation-driven /
  3. Struts2中的ModelDriven机制及其运用
  4. HDU 4079 Happy Telephones 简单题
  5. C# WebBrowser 设置代理完全解决方案
  6. 《Orange’s 一个操作系统的实现》3.保护模式4----LDT(Local Descriptor Table)
  7. Kubernetes 1.4安装后查看记录
  8. 《Linux编程》学习笔记 ·001【基本操作、常用命令】
  9. Ubuntu 16.04 安装 MPI(Message Passing Interface)
  10. pandas作图_pandas绘图