策略模式

概述

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

UML

实现

Strategy.java,策略类,定义算法的公共接口。

public abstract class Strategy {   // 算法方法   public abstract void algorithmInterface();}

ConcreteStrategyA.java,算法A,封装了具体算法,继承Strategy。

public class ConcreteStrategyA extends Strategy {   @Override   public void algorithmInterface() {      System.out.println("算法A实现");   }}

ConcreteStrategyB.java,算法B。

public class ConcreteStrategyB extends Strategy {   @Override   public void algorithmInterface() {      System.out.println("算法B实现");   }}

ConcreteStrategyC.java,算法C。

public class ConcreteStrategyC extends Strategy {   @Override   public void algorithmInterface() {      System.out.println("算法C实现");   }}

Context.java,上下文环境,维护Strategy引用。

public class Context {   private Strategy strategy;   public Context(Strategy strategy) {      this.strategy = strategy;   }   public void contextInterface() {      strategy.algorithmInterface();   }}

StrategyTest.java,客户端代码。

public class StrategyTest {   public static void main(String[] args) {      Context context;      context = new Context(new ConcreteStrategyA());      context.contextInterface();      context = new Context(new ConcreteStrategyB());      context.contextInterface();      context = new Context(new ConcreteStrategyC());      context.contextInterface();   }}

优缺点

优点

1、   提供了一种替代继承的方法,而且既保持了继承的优点(代码重用),还比继承更灵活(算法独立,可以任意扩展);

2、   避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展;

3、   遵守大部分GRASP原则和常用设计原则,高内聚、低偶合;

4、   易于进行单元测试,各个算法区分开,可以针对每个算法进行单元测试;

5、   ……

缺点

1、   因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量;

2、   选择何种算法需要客户端来创建对象,增加了耦合,这里可以通过与工厂模式结合解决该问题;

3、   程序复杂化。

实例

需求

商场收银系统,实现对不同情况(正常收费、折扣收费、返利收费等)的收费。

实现

CashSuper.java,现金收费父类。

/* 现金收费父类 */public abstract class CashSuper {   /* 收取现金方法,参数为商品原价,返回值为当前价 */   public abstract double acceptCash(double money);}

CashNormal.java,正常收费。

/* 正常收费 */public class CashNormal extends CashSuper {   @Override   public double acceptCash(double money) {      return money;   }}

CashRebate.java,打折收费。

/* 打折收费 */public class CashRebate extends CashSuper {   /* 折扣率 */   private double moneyRebate;      public CashRebate(double moneyRebate) {      this.moneyRebate = moneyRebate;   }    @Override   public double acceptCash(double money) {      return money * moneyRebate;   }}

CashReturn.java,返利收费。

/* 返利收费 */public class CashReturn extends CashSuper {   /* 返利满足条件 */   private double moneyCondition;   /* 满足条件后返回值 */   private double moneyReturn;      public CashReturn(double moneyCondition, double moneyReturn) {      this.moneyCondition = moneyCondition;      this.moneyReturn = moneyReturn;   }    @Override   public double acceptCash(double money) {      double result = 0;      result = money - Math.floor(money / moneyCondition) * moneyReturn;      return result;   }}

CashContext.java,维护CashSuper对象。

public class CashContext {    private CashSuper cs;      public CashContext(CashSuper cs) {      this.cs = cs;   }      public double getResult(double money) {      return cs.acceptCash(money);   }}

CashTest.java,客户端。

public class CashTest {   public static void main(String[] args) {      double money = 500;      CashContext context;      context = new CashContext(new CashNormal());      double normal = context.getResult(money);      System.out.println("正常收费:" + normal);      context = new CashContext(new CashRebate(0.8));      double rebate = context.getResult(money);      System.out.println("八折收费:" + rebate);      context = new CashContext(new CashReturn(200, 100));      double retur = context.getResult(money);      System.out.println("满200返100:" + retur);   }}

总结

策略模式和简单工厂模式的区别

相同点

1、   都是用到了封装、继承、多态;

2、   都抽出一个接口或者抽象类,针对不同的情况,有不同的实现类。

不同点

1、   使用方式不同,工厂是静态的,策略的上下文是需要创建对象的;

2、   工厂产生的是对象,不同情况下产生不同的对象;

3、   策略产生的是策略,或者说是算法,不同情况下使用不同的算法。

结论

无论何种设计模式,都是基于面相对象的三大特性,即封装、继承、多态。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后端之路

源码解析之ConcurrentHashMap

前言 相信有并发经验的小伙伴对于ConcurrentHashMap不会陌生。 上一篇我们描述了cow容器 cow容器之CopyOnWriteArrayList,...

3645
来自专栏androidBlog

装饰者模式及其应用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/...

1512
来自专栏非典型技术宅

iOS实践:一步步实现星级评分1. 创建星星2. 优化3. 灵异事件

1464
来自专栏函数式编程语言及工具

Akka(32): Http:High-Level-Api,Route exception handling

  Akka-http routing DSL在Route运算中抛出的异常是由内向外浮出的:当内层Route未能捕获异常时,外一层Route会接着尝试捕捉,依次...

2116
来自专栏Ryan Miao

从国家统计局爬下来的地区信息

发现地区编码网上流传了很多版本。有很多崇文区,玄武区之类的。于是想了想,还是自己做一份。不敢保证没问题,但还没遇到问题。 首先,从网上找到一个大神写的jsoup...

3526
来自专栏一个会写诗的程序员的博客

【Kotlin 反应式编程】第1讲 你好,Reactive Programming

【Kotlin 反应式编程】第1讲 你好,Reactive Programming

752
来自专栏Java与Android技术栈

当RxJava遇到AOP

公司打算开发一款全新的To C产品,因此我开始做一些搭建框架的事儿以及POC。新的产品能够使用一些比较新的技术,在新产品中我大量使用了Rx。这就导致了原先的AO...

812
来自专栏算法+

声音变调算法PitchShift(模拟汤姆猫) 附完整C++算法实现代码

上周看到一个变调算法,挺有意思的,原本计划尝试用来润色TTS合成效果的。 实测感觉还需要进一步改进,待有空再思考改进方案。 算法细节原文,移步链接: http:...

48510
来自专栏mathor

Hanoi(汉诺塔)

1012
来自专栏练小习的专栏

js检测图形碰撞笔记

图形平面碰撞的检测方式就是判断点是否同时在两个对象中。比如这个笔记中的例子 <!DOCTYPE html> <html> <head> <title>i...

2159

扫码关注云+社区