假设现在要设计一个麦各类书籍的电子商务汪涵的(Shoping Card)系统,一个最简单的情况就是把所有货品的单价乘上数量,但是实际情况肯定要比这复杂。比如本网站可能对所有的教材类图书实行每本两元的折扣;对连环画类图书提供每本10%的促销折扣,而非教材类的计算机图书有5%的折扣;对其余书没有折扣。由于有这样复杂的折扣算法,使得价格计算问题需要系统地解决。

那么怎么样才能解决这个问题呢?

其实,解决方法不止一种,例如我们可以把所有逻辑放在客户端利用条件语句判断决定使用哪一种算法;也可以利用继承在子类里面实现不同打折算法;还可以利用策略模式将环境和各种算法分开,将具体实现与客户端解耦。

实现这个策略的UML图如下:

抽象策略类(DiscountStrategy)

package com.strategy.booksale;
/*** 抽象策略类,定义了抽象算法* @author LLS**/
abstract public class DiscountStrategy
{//抽象方法abstract public double calculateDiscount();
}

10%的折扣促销类(PercentageStrategy)

package com.strategy.booksale;
/*** 折扣销售图书类* @author LLS**/
public class PercentageStrategy extends DiscountStrategy
{   //保存单价、数量、总额private double percent = 0.0;private double price = 0.0;private int copies = 0;public PercentageStrategy(double price, int copies,double percent){   this.percent=percent;this.price = price;this.copies = copies;}public double getPercent(){return percent;}public void setPercent(double percent){this.percent = percent;}//覆盖父类的抽象方法public double calculateDiscount(){return copies * price * percent;}}

平价打折类(FlatRateStrategy)

package com.strategy.booksale;
/*** 平价销售图书,不进行打折算法类* @author LLS**/
public class FlatRateStrategy extends DiscountStrategy
{//保存图书单价、数量、总额private double amount;private double price = 0;private int copies = 0;public FlatRateStrategy(double price, int copies){this.price = price;this.copies = copies;}public double getAmount(){return amount;}public void setAmount(double amount){this.amount = amount;}//覆盖了抽象类的方法public double calculateDiscount(){return copies * amount;}
}

不打折类(NoDiscountStrategy)

package com.strategy.booksale;public class NoDiscountStrategy extends DiscountStrategy
{private double price = 0.0;private int copies = 0;public NoDiscountStrategy(double price, int copies){this.price = price;this.copies = copies;}public double calculateDiscount(){return price*copies;}
}

维护抽象类的引用

package com.strategy.booksale;
/*** 维护抽象策略类的引用* @author LLS**/
public class Context {//维护策略抽象类的一个引用DiscountStrategy discountStrategy;//传入具体策略对象public Context(DiscountStrategy discountStrategy) {this.discountStrategy=discountStrategy;}//根据具体策略对象调用其方法public void ContextInterface(){discountStrategy.calculateDiscount();}
}

客户端测试类(Test)

package com.strategy.booksale;public class Test {public static void main(String[] args){//维护抽象策略类Context context;//采用平价打折,单价为10元,数量5本context=new Context(new FlatRateStrategy(10, 5)); //采用百分比打折10%context=new Context(new PercentageStrategy(10, 5,0.1));}
}

这样利用策略模式已经解决了多种打折的问题,但是你有没有发现策略只是实现了在不同打折方法或不同算法行为之间得灵活切换,并没有控制实例化哪一个算法,需要用哪一个优惠方式是由客户端决定的,所以客户端与具体的实现类之间耦合性很大,还需要进一步解耦。

策略模式更注重于n选1的情况,这也就是说如果我想组合几种不同的打折策略,策略就会显得不恰当,因为你需要将多个打折方法都写到一个类里面去,为解决这种情况,可以配合装饰(Decorator)模式一起使用。

装饰模式适合给一个类添加额外的职责,并且对客户端透明。

我们来看一张表示装饰模式的图,这张图即表明了它的添加功能特性也它的透明性。

大家很容器想到简单工厂,它就是一个封装产生对象的过程的类,通过传入字符串的方式决定实例化哪一个类,但是它也有不足,如果我们需要加入新的打折策略时,就需要改动工厂里面的代码,这违反了OCP原则。

我们可以利用反射来动态决定实例化哪个策略,配置文件和反射类如下:

配置文件设置

<?xml version="1.0" encoding="UTF-8"?>
<config><!-- 标签 --><strategy-class><!-- 折扣策略类 --><strategy id="com.strategy.booksale.DiscountStrategy" class="com.strategy.booksale.PercentateStrategy"></strategy></strategy-class>
</config>

反射类

package com.strategy.booksale;import java.util.HashMap;
import java.util.Map;import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;/*** 反射类* @author LLS**/
public class Reflection{//采用饿汉式单利模式,可能占内存private static Reflection instance=new Reflection();//系统缺省配置文件名称private final String sysconfig="sys-config.xml";//保存具体策略键值对private Map strategyMap =new HashMap();//读取出来的document对象private Document doc;private  Reflection(){try {doc=new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));} catch (Exception e) {e.printStackTrace();}}//得到实例 的方法public static Reflection getInstance() {return instance;}/*** 根据策略 编号,取得的具体策略* @param beanId* @return*/public synchronized Object  getStrategyObject(Class c){//判断serviceMap里面是否有service对象,没有创建,有返回if (strategyMap.containsKey(c.getName())) {return strategyMap.get(c.getName());}//返回指定ID的Element对象Element strategyElement=(Element)doc.selectSingleNode("//strategy[@id=\""+c.getName()+"\"]");String className=strategyElement.attributeValue("class");Object strategyObject=null;try {strategyObject = Class.forName(className).newInstance();strategyMap.put(c.getName(), strategyObject);} catch (Exception e) {e.printStackTrace();throw new RuntimeException();}return strategyObject;}
}

改写后的客户端如下:

package com.strategy.booksale;public class Test {public static void main(String[] args){//维护抽象策略类Context context;//利用反射动态决定使用哪一种打折策略DiscountStrategy discountStrategy=(DiscountStrategy)Reflection.getInstance().getStrategyObject(DiscountStrategy.class);//客户端只需要识别策略抽象类即可,与具体的算法解耦context=new Context(discountStrategy);}
}

这样一来客户端完全不知道有什么算法,也不知道该实例化哪一个,减少了客户端的职责。

最后,我们用装饰模式来解决策略不可以组合多个打折方式的不足,装饰模式的主要作用即可以给一个对象动态添加多种功能,下面是我画的类图,有了类图代码可以自己实现,让它们共同实现了同一个抽象类。

左边部分是装饰模式负责动态组合各种打折方法,右边是策略模式动态选择其中一种打折策略,之所以它们的功能可以一起使用,这里是因为他们实现了一个共同的接口 (Interface)。

有些问题如果我们站在接口或抽象类的角度去考虑,用接口和抽象的方式去思考,有时问题会容易解决一些,而不要一直在某个具体的类范围内考虑问题,即把思考的角度范围扩展,从高层次考虑更容容易解决下面层次的问题。

思想上移一些,站在这个问题的更高一层。

转载于:https://www.cnblogs.com/lilongsheng/p/3226038.html

[置顶] J2EE (八) 策略模式+装饰模式+反射(java)相关推荐

  1. 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...

  2. 策略模式及简单Java案例代码实现

    说明:本文是<大话设计模式>的学习记录及结合网上相关信息编写,原书代码例子采用C#编写,本文采用Java稍加改写.如有不当,欢迎指正,共同进步. 1.策略模式概述:      策略模式(P ...

  3. [设计模式] ------ 策略模式实战:java中替代if-else的大段逻辑

    java中用策略模式替代if-else的大段逻辑 问题: java本来是一门以面向对象为主的语言,但很多人嘴上说着java面向对象,然后除了表映射实体之外,其他的还是面向过程的思路. 就比如今天要说的 ...

  4. java怎么在记事本里写过运行_[置顶] 如何运行用记事本写的java程序

    今天用记事本写了一个java程序,测试能运行,现在把它分解成几个步骤,利于大家理解: 1. 新建一个记事本,后缀名是  .java  :然后在里面写一段java的代码,如图: 2.把写好的java文件 ...

  5. 【设计模式】结构型模式——装饰模式

    文章目录 一.定义 二.问题 三.解决方案 四.实现 五.UML图 六.装饰模式应用场景 七.总结 优点 缺点 八.与其他模式的关系 一.定义 装饰模式是一种结构型设计模式, 允许你通过将对象放入包含 ...

  6. 十四、策略模式——你要黄焖鸡、手撕鸡、大盘鸡、叫花鸡都可以,指定一个吧

    文章目录 策略模式 1.实现策略模式 1.1 定义接口和实现类 1.2 客户端切换算法方便 2.多例工厂与静态策略模式 3.反射与动态策略模式 总结 设计模式是面向问题.场景而总结产生的设计思路.是解 ...

  7. 从业务出发,来谈谈策略模式,清爽的飞起~

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 路易小七 来源 | cnblogs.com/l ...

  8. [设计模式] ------ 策略模式

    策略模式 它定义了算法家族,分别封装起来,让他们直接可以互相替换,此模式让算法的变化,不会影响到使用算法的客户 其实很简单,可能很多人都用到了,只不过还不知道这就是策略模式而已. 比如定义一个接口A, ...

  9. 1小时搞懂设计模式之策略模式

    1 什么是策略模式 简单一句话理解就是通过不同的方式来完成一件事.我们拿生活举例:年终将至又到了涨工资的时候了,领导会根据你今年工作表现来将员工分为三种: 工作不积极的坏员工 对于坏员工执行不涨薪策略 ...

最新文章

  1. Mac 下 IDEA 启动慢的问题
  2. cpld xilinx 定义全局时钟_AutoSAR中的时钟同步机制
  3. 网络营销外包排名没效果想必是这些因素影响了网络营销外包
  4. socket编程 及select poll epoll示例
  5. mysql的innodb表生成的物理文件_MySQL innodb表使用表空间物理文件复制或迁移表
  6. srs rtmp从监听到接收到新连接的过程分析
  7. jquery复选框 选中事件 及其判断是否被选中_常用笔记
  8. SCI EI 期刊等讨论站点
  9. 《信息安全系统设计基础》实验五 简单嵌入式WEB服务器实验
  10. java语言之数组-----选择排序
  11. Linux镜像文件提取,如何提取linux 系统镜像文件
  12. VSCode 设置为 Monaco字体
  13. 【第四课】UAV倾斜摄影测量三维建模技术软件——Smart 3d
  14. 使用三边定位算法进行室内定位
  15. 使用PowerShell查看Windows 补丁记录并写入数据库
  16. 【Unity3D日常开发】应粉丝邀约,写一篇单例模式在Unity的实际应用,记得一键三连哦
  17. 持安科技孙维伯:实战零信任最佳实践
  18. 计算机的人分类,计算机的分类
  19. 基于微信小程序公交查询系统设计与实现
  20. php面向对象手册,php学习笔记之面向对象

热门文章

  1. 线性表中顺序表基本运算的实现---数据结构(C)
  2. RESTful开发风格
  3. 二叉树的基本操作(建立与遍历)
  4. linux哪个系统能编译固件,rk3328编译Linux固件
  5. Matlab编写一个脚本计算e,Matlab编程基础I脚本.PPT
  6. oracle 7 客户端,windows 7环境下配置oracle 11g 客户端
  7. 面试题:二叉树中和为某一路径
  8. virtualbox display size
  9. Spring(二)--FactoryBean、bean的后置处理器、数据库连接池、引用外部文件、使用注解配置bean等...
  10. oracle新建对象 权限管理