策略模式

概述

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

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 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

泛型List<T>使用示例

代码来源于"c#高级编程(第4版)",略作修改 using System; using System.Collections; using System.C...

1767
来自专栏菩提树下的杨过

Linq排序效率 Vs 快速排序效率

 1 using System;  2 using System.Collections;  3 using System.Collections.Generi...

1868
来自专栏along的开发之旅

C#中字符,字符串的大小写转换

对字符串来说,"string".ToLower()和"string".ToUpper()可以基本满足需求,但是当需要将首字母大写的时候,这两个函数就有点不够用了...

811
来自专栏大内老A

由for V.S. for each想到的

一直想写一系列如何提高Performance和Scalability的文章,把我的相关经验和所知道的相关的技巧同大家分享。前一阵在园子里有一篇讨论for eac...

1828
来自专栏菩提树下的杨过

运算符重载,以及迭代器[foreach]示例

 以下代码来源于"c#高级编程(第4版)",只不过我对它做了一些注释和修改 using System; using System.Collections; ...

1848
来自专栏owent

POJ PKU 2155 Matrix 解题报告

题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=2155

821
来自专栏偏前端工程师的驿站

自定义迭代器使用foreach

  foreach遍历集合好处很多,因为.net framework在foreach中已经做了try...catch和dispose的操作。那么如果想自定义一个...

1807
来自专栏跟着阿笨一起玩NET

c#委托把方法当成参数

941
来自专栏Albert陈凯

2018-09-06 字符串中判断存在的几种模式和效率(string.contains、string.IndexOf、Regex.Match),stringregex

字符串中判断存在的几种模式和效率(string.contains、string.IndexOf、Regex.Match),stringregex

471
来自专栏张善友的专栏

Mono 3.2 测试NPinyin 中文转换拼音代码

C#中文转换为拼音NPinyin代码  在Mono 3.2下运行正常,Spacebuilder 有使用到NPinyin组件,代码兼容性没有问题。 using S...

1877

扫码关注云+社区