一 概述

我们这个社会上的事情大概率都符合八二法则,软件领域也一样。例如你学习一门编程语言,工作中常用的类来来回回也就那么几十个。那么多设计模式,最常被人使用的也就那么几种,所以我们在做事情的时候应该首先着眼于那20%。

策略模式算是设计模式中简单而又常用的了。

1.1 定义

策略模式定义了一系列的算法,并将每一个算法封装起来,使他们可以相互替换。

  • 策略模式属于行为型模式
  • 策略模式提供了一组算法给客户端调用,使得客户端能够根据不同的条件来选择不同的策略来解决不同的问题
  • 如排序算法,可以使用冒泡排序、快速排序等等

1.2 使用场景

当你写代码的时候发现一个操作有好多种实现方法,而你需要根据不同的情况使用 if-else 等分支结构来确定使用哪种实现方式的时候,想一想这个模式。

1.3 UML 类图


角色说明

  • Stragety (抽象策略类):抽象类或接口,提供具体策略类需要实现的接口
  • ConcreteStragetyA、ConcreteStragetyB(具体策略类):具体的策略实现,封装了相关的算法实现
  • Context(环境类):用来操作策略的上下文环境

二 实现

2021年的2月14号,王二狗和牛翠花约好在天津之眼约定终身,二狗打扮一番后准备出发,此时问题来了:是坐公交去呢,还是打滴滴快车呢?天气看起来也不错,要不骑共享单车吧,省钱还锻炼身体。

对应到编程领域就是:目前有三种策略可以实现一个特定的目的,使用何种策略取决于调用者(客户端).

2.1 普通实现

如果我们正常写代码,平时也应该这样,首先保证把功能正确的实现了,然后慢慢重构,设计模式都是在不断的重构当中应用的。 王二狗会调用 goToTianJinEye() 方法,根据自己的实际情况,选择某一种出行方式。

public class TrafficFeeCalculator {public int goToTianJinEye(String way, int distance) {int trafficFee = 0;switch (way) {case "bus":if (distance < 10)trafficFee = 4;elsetrafficFee = 6;break;case "didi":if(distance<3)trafficFee = 8;else trafficFee=8+(distance-3)*3;break;case "sharedBicyle":trafficFee = 2;break;default:break;}return trafficFee;}
}

那么这么写有什么弊端呢?

  • 每一种出行方式的交通花费的计算方式都写在了 TrafficFeeCalculator 类中,这个类承担的职责较多,违反了单一职责原则
  • 假如王二狗突然想自己开车去,那就需要修改 goToTianJinEye 这个方法了。违反了开闭原则。

2.2 使用策略模式

以上的场景非常适合使用策略模式,将多种不同的实现算法封装,然后客户端根据不同策略分别调用相应的算法。

2.2.1 封装不同的实现算法

首先定义一个策略接口,规定算法的同一操作

public interface CalculateStrategy {int calculateTrafficFee(int distance);
}

2.2.2 封装各个算法

    //乘坐公交车算法
public class ByBus implements CalculateStrategy {@Overridepublic int calculateTrafficFee(int distance) {return distance<10?4:6;}
}
//乘坐滴滴快车算法
public class ByDiDiExpress implements CalculateStrategy {@Overridepublic int calculateTrafficFee(int distance) {return distance<3?8:(8+(distance-3)*3);}
}
//骑共享单车算法
public class BySharedBicycle implements CalculateStrategy {@Overridepublic int calculateTrafficFee(int distance) {return 2;}
}

2.2.3 使用算法

public class TrafficFeeCalculator {...public int goToTianJinEye(CalculateStrategy strategy, int distance){return strategy.calculateTrafficFee(distance);}
}

2.2.4 客户端调用

根据情况,构建相应的算法类实例,传入计算器计算即可。

    public static void main(String[] args) {TrafficFeeCalculator calculator=new TrafficFeeCalculator();System.out.println(String.format("乘坐公交车到天津之眼的花费为:%d块人民币",calculator.goToTianJinEye(new ByBus(),10)));System.out.println(String.format("乘坐滴滴快车到天津之眼的花费为:%d块人民币",calculator.goToTianJinEye(new ByDiDiExpress(),10)));System.out.println(String.format("骑共享单车到天津之眼的花费为:%d块人民币",calculator.goToTianJinEye(new BySharedBicycle(),10)));}

输出结果:

乘坐公交车到天津之眼的花费为:6块人民币
乘坐滴滴快车到天津之眼的花费为:29块人民币
骑共享单车到天津之眼的花费为:2块人民币

二狗为了早点见到自己心爱的牛翠花,最终选择了滴滴快车,贵是贵了点,但是快!

三 总结

3.1 特点

是不是感觉讲设计模式的文章都有一个特点,使用了设计模式反而比不使用设计模式使程序看起来更加复杂,而不是更加简单。那是因为每篇文章的示例都是无实际使用意义的示例代码,实际情况是程序非常复杂才需要使用到设计模式。一个大型程序是不断迭代出来的,一开始肯定不长那样,程序员日常接到一个开发任务也不要过多的想,这个我应该用个什么设计模式呀?先把功能实现了,然后回头看看有没有遵循面向对象编程6大原则,如果没有想想怎么改进,然后设计模式就登场了。。。

3.2 优点

  • 策略类可以互相替换
    由于策略类都实现同一个接口,因此他们能够互相替换。
  • 耦合度低,方便扩展
    增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合开闭原则。
  • 避免使用多重条件选择语句(if-else 或者 switch)

3.3 缺点

  • 策略的增多会导致子类的也会变多
  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类

四 Android中的源码实例分析

之前我们用的 ListView 时都需要设置一个 Adapter,而这个 Adapter 根据我们实际的需求可以用 ArrayAdapter、SimpleAdapter等等,这里就运用到策略模式。

4.1 ListView 的简单用法

    listView = (ListView)findViewById(R.id.list_view);// 使用 ArrayAdapterlistView.setAdapter(new ArrayAdapter<String>(this,R.id.item,new String[] {"one","two"}));// 使用 BaseAdapterlistView.setAdapter(new BaseAdapter() {@Overridepublic int getCount() {return 0;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return null;}});

4.2 相关源码分析

  public class ListView extends AbsListView { // 相当于环境类@Overridepublic void setAdapter(ListAdapter adapter) { // 设置策略,即 adapter// 其他代码略}}public interface ListAdapter extends Adapter { // 抽象策略接口}// 具体策略类 BaseAdapter,实现 ListAdapter 接口public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {        }// 具体策略类 ArrayAdapter,继承 BaseAdapter,即实现 ListAdapter 接口public class ArrayAdapter<T> extends BaseAdapter implements Filterable,ThemedSpinnerAdapter {        }

4.3 总结

  • 通过设置不同的 Adapter(即不同的策略),我们就可以写出符合我们需求的 ListView 布局
  • 另外,动画中的插值器(ValueAnimator 的 setInterpolator 方法)也是有运用到策略模式,有兴趣的可以去看下

JAVA设计模式之策略模式相关推荐

  1. Java设计模式之策略模式与状态模式

    一.策略模式定义 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们之间可以相互替换,策略模式可以在不影响客户端的情况下发生变化. 好了,定义看看就完了,我知道你很烦看定义. 二.策 ...

  2. Java设计模式之策略模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

  3. Java设计模式之策略模式+工厂模式+模板模式

    Java设计模式之策略模式+工厂模式+模板模式 1.策略模式+工厂模式+模板模式 个人的理解:实际开发工程中,一些业务很复杂的逻辑使用很多的 if 或者 if···else 语句,不利于维护和扩展,为 ...

  4. 【Java设计模式】策略模式

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景知识 策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法.比如每 ...

  5. Java 设计模式之策略模式

    一.了解策略模式 1.1 什么是策略模式 策略模式 (Strategy Pattern) 是指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换.此模式让算法的变化独立于使用算法的客 ...

  6. java解决策略膨胀_折腾Java设计模式之策略模式

    简介 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式.简单理解就是一组算法,可以互换,再简单点策略就是封装算法. 意图 定义一 ...

  7. 【设计模式】java设计模式之 -- 策略模式

    对于代码中总是会有需要变化的部分和需要固定不变的部分.对于需要变化的部分,一般可以采用继承的方式,让子类对父类的方法进行重写,以改变已有的行为:如果变化的部分并不是所有子类都必须要有的,那就可以采用接 ...

  8. Java设计模式之策略模式---写的比较有趣,推荐大家看看

    原文:http://blog.csdn.net/jason0539/article/details/45007553 背景 在软件开发中常常遇到这种情况,实现某一个功能有多种算法或者策略,我们可以根据 ...

  9. 《Java设计模式之策略模式》

    <二 >策略模式   相信很多人都玩过魔兽世界这款游戏,它里面的战士有三种姿态:防御.狂暴.战斗,那么在不同的场景下我们需要使用不通的姿态,比如当MT抗怪就需要使用防御姿态,战场需要使用战 ...

  10. Java设计模式之——策略模式

    策略模式的简单介绍 在软件开发中常常遇到这样的情况:实现某一个功能可以有多种算法或者策略,我们根据事件情况选择不同的算法或者策略来完成该功能.例如,排序算法,可以使用插入排序.归并排序.冒泡排序等. ...

最新文章

  1. mysql行转列和列转行_mysql 行转列和列转行实例详解
  2. ThreadLocal工作原理和内存泄漏的预防
  3. Win11系统中的Thumbs.db文件可以删除吗?
  4. tabcontrol设置当前活动页
  5. STL容器-queue队列
  6. 离心泵CAE_2_ICEM剖分网格_2_叶轮流道
  7. 最新emoji表情代码大全_三十而已表情包下载-三十而已表情包大全最新下载
  8. 北京理工大学OJ的Mid难度题目的题解
  9. 2022双十一投影仪选购清单,知名博主分享2022投影仪推荐名单
  10. vue中keep-alive、activated的探讨和使用
  11. 计算机设置休眠密码,win10系统如何设置电脑待机密码?windows10设置待机密码图文教程...
  12. C/C++语言ODBC连接SqlServer数据库
  13. 基于javaweb的校园外卖点餐系统(java+ssm+jsp+mysql)
  14. 邬贺铨院士:5G技术影响智联网的关键点
  15. unity ugui改变width,height,pos
  16. Spring boot项目实现跨域,java
  17. Jmeter书中不会教你的(94)——将时间戳转换为日期格式
  18. 利用招行香港一卡通和美国Scottrade开设港股和美股的攻略
  19. 中国联通用户的GPRS和彩信设置方法
  20. 190528每日一句,在最黑暗的时刻,我们必须集中精神寻找光明

热门文章

  1. 解决 Android 7.0 SQLiteCantOpenDatabaseException: unknown error (code 14)
  2. hls视频demo搭建简易服务器模拟运行
  3. glide 设置宽高_glide如何设置图片大小
  4. androidbenchmark和iphonebenchmark这两页面中设备信息爬虫
  5. 目标客户画像_数据运营实战(一):细分目标人群,结合用户画像的实践
  6. 智能睡眠监测带扣案列/APP/小程序/网站
  7. 遇到问题---linux--shell--Argument list too long
  8. c语言 printf 输出 long 整型
  9. android 设置全屏
  10. 手机微信收不到消息提醒,这样设置就能轻松解决