工厂模式策略者模式责任链模式综合应用
Posted loveyoumi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了工厂模式策略者模式责任链模式综合应用相关的知识,希望对你有一定的参考价值。
设计模式的具体运用:
简单工厂模式、策略者模式、责任链模式定义与使用
classLoader的具体运用
自定义的classloader 来动态加载类
程序功能设计:
在商城购物时,商城可能会在特殊的日子、或者依据会员等级,对结算的商品进行价格上的优惠,本篇将模拟价格计算时,优惠策略的动态选择和优惠策略的链式处理;
程序流程图:
图中有两种价格优惠计算的流程图:
流程2:价格优惠计算时直接采用责任链模式进行处理,设计和流程都比较简单,作者更倾向于这种流程设计;但为了练习和使用更多的设计模式,所以本篇采用了流程2的方法实现;
流程1:将价格优惠计算分成了特殊和固定价格优惠(比如:会员值。或则满额减等),这种流程模式在进入到特殊优惠条件时,可以采用责任链的方式实现,而固定价格优惠计算时,可以采用策略者模式进行实现;
UML 图:
源码:
定义价格策略接口
/** * 商品价格的计算策略 */ public interface PriceStrategy { double calcPrice(double price); }
定义一个注解,用于工厂动态加载和创建PriceStrategy(价格策略)对象
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FixedPrivilegePrice { double max() default 0; double min() default Integer.MAX_VALUE; }
两个简单的价格策略算法的实现,这里利用注解的两个属性:min 和 max 属性,定义策略类的使用要求:即计算的价格必须在指定的价格区间内
@FixedPrivilegePrice(min=100,max=500) public class SimpleStrategy1 implements PriceStrategy { @Override public double calcPrice(double price) { return price * 0.8; } }
@FixedPrivilegePrice(min=500,max=Integer.MAX_VALUE) public class SimpleStrategy2 implements PriceStrategy { @Override public double calcPrice(double price) { return price * 0.7; } }
默认的价格优惠策略类,用于无可用策略时,将不对价格进行优惠
public class DefaultPriceStrategy implements PriceStrategy { @Override public double calcPrice(double price) { return price; } }
定义特殊价格的优惠策略接口,用于特殊价格优惠策略的链式处理;next() 方法在这里是责任链模式实现的关键;
/** * 用于价格计算时,提供特殊的价格优惠算法 * */ public interface PricePrivilege extends PriceStrategy { PricePrivilege next(); void register(PricePrivilege pp); }
抽象类,实现对象链的选择和注册;
public abstract class AbstractPricePrivilege implements PricePrivilege { protected PricePrivilege next; public PricePrivilege next() { return next; } @Override public void register(PricePrivilege pp) { next = pp; } }
特殊价格优惠策略两个简单实现:
public class Birthday extends AbstractPricePrivilege { @Override public double calcPrice(double price) { //会员生日一律9折优惠 return price * 0.9; } }
public class PreferentialCar extends AbstractPricePrivilege { @Override public double calcPrice(double price) { // 这是一张满100百减10的优惠卡 if(price >= 100) price -= 10; return price; } }
PricePrivilege 的工厂接口
public interface IPriceStratedyFactory { PriceStrategy createAndGet(double price); }
PricePrivilege 的工厂实现,
这个工厂类是动态加载和动态选择策略的核心:
1, 动态加载策略: 该工厂将从给定的一个目录中,动态加载可用的所有策略,并将这些策略保存到一个链表中;(并且可以提供一个动态添加和删除策略的接口,或者在从给定目录中动态加载策略时,启动一个定时检查器,用于间断性添加和删除策略,但这种方法
需要考虑策略的实效性;———————————— 后续思想,本篇未实现;)
2,动态策略选择: 每一个策略类都使用了FixedPrivilegePrice 这个注解,本篇该注解使用了两个属性:min 和max ,表示价格的最大值和最小值,当结算价格在这个区间时,就选择这种策略;当然这只是简单的价格判断,也可以根据实际添加其他的属性用于策略的选择;
import java.io.File; import java.io.FilenameFilter; import java.net.URL; import java.util.HashSet; public class PriceStrategyFactory implements IPriceStratedyFactory { public PriceStrategy createAndGet(double price) { PriceStrategy ps = findPriceStrategyInHolder(price); if(ps == null) { ps = PriceStrategyHolder.DEFAULT_PRICE_STRATEGY; } return ps; } private PriceStrategy findPriceStrategyInHolder(double price) { for(PriceStrategy ps : PriceStrategyHolder.priceStrategy) { FixedPrivilegePrice fpp = ps.getClass().getAnnotation(FixedPrivilegePrice.class); if(matchCondition(price ,fpp)) return ps; } return null; } private boolean matchCondition(double price ,FixedPrivilegePrice fpp) { return price >= fpp.min() && price <= fpp.max(); } static private class PriceStrategyHolder { static private final PriceStrategy DEFAULT_PRICE_STRATEGY = new DefaultPriceStrategy(); static private HashSet<PriceStrategy> priceStrategy = new HashSet<>(); static final private LoadPriceStrategyUtil LOAD_UTIL = new LoadPriceStrategyUtil(); static { LOAD_UTIL.classLoder(priceStrategy); } } static private class LoadPriceStrategyUtil{ static final private String STRATEGY_URL = "learn.design.model.demo1"; void classLoder(HashSet<PriceStrategy> pss) { String[] classFiles = findClassFileFromPath(); if(classFiles == null) return; DynamicLoaderClass dlc = new DynamicLoaderClass(); for(String classFileName : classFiles) { try { String className = generateClassName(classFileName); Class<?> cls = dlc.loadClass(className); FixedPrivilegePrice fpp = cls.getAnnotation(FixedPrivilegePrice.class); if(fpp != null ) { pss.add((PriceStrategy) cls.newInstance()); } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e1) { } } } String generateClassName(String classFileName) { return STRATEGY_URL + "." + classFileName.substring(0 ,classFileName.indexOf(".")); } String[] findClassFileFromPath() { //符号替换 String loaderUrl = STRATEGY_URL.replace(".", "/"); URL url = ClassLoader.getSystemResource(loaderUrl); if(url == null)return null; return new File(url.getPath()).list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(".class"); } }); } } }
提供一个自定义的类加载器工具,用于动态的加载给定目录下的class文件,默认从项目的classpath路径下查找;
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class DynamicLoaderClass extends ClassLoader { private String path; public DynamicLoaderClass(){ this(Thread.currentThread().getContextClassLoader().getResource("").getPath()); } public DynamicLoaderClass(String path) { this.path = path; } @Override public Class<?> loadClass(String className) throws ClassNotFoundException { Class<?> cls = loadClassByParent(className); if(cls == null) cls = loadClassBySelf(className); return cls; } private Class<?> loadClassBySelf(String className) throws ClassNotFoundException { return findClass(className); } private Class<?> loadClassByParent(String className){ Class<?> cls = null; try{ cls = super.loadClass(className); }catch (ClassNotFoundException e) { //load class failed; } return cls; } @Override protected Class<?> findClass(String className) throws ClassNotFoundException { byte[] b = getResourceForCurrentPath(className); return defineClass(className, b, 0, b.length); } private byte[] getResourceForCurrentPath(String className) throws ClassNotFoundException{ return getResourceForPath(genrateResourcePath(className)); } private byte[] getResourceForPath(String resourcePath) throws ClassNotFoundException { checkResourceIsExist(resourcePath); return readResource(resourcePath); } private byte[] readResource(String resourcePath) throws ClassNotFoundException { byte[] result = null; File file = new File(resourcePath); FileInputStream fis = null; try { fis = new FileInputStream(file); result = new byte[fis.available()]; fis.read(result); fis.close(); } catch (FileNotFoundException e) { // This should only happen with multithreading } catch (IOException e) { throw new ClassNotFoundException(); } return result; } private void checkResourceIsExist(String resourcePath) throws ClassNotFoundException { File file = new File(resourcePath); if(!file.exists()) throw new ClassNotFoundException(); } private String genrateResourcePath(String className){ return path + "/" + className.replace(".", "/") +".class"; } }
价格处理者接口,接口规定:价格的最终结算价格将在这个接口中处理完成;用户不需要关心如何完成,以及是否使用了价格的策略,相当于将所有的价格优惠策略都封装和隐藏起来,实现与客户端的分离
/** * 提供对商品价格的计算方式 * */ public interface PriceHandler { double calcPrice(double price ,PricePrivilege pp); }
定义一个书记类型商品的价格处理器,
1,该类将从用户那里获取用户可以使用的特殊优惠策略,本篇中直接传入了特殊优惠策略的对象,这里是可以改进的:传入特殊优惠策略的满足条件,比如:用户领取了一张优惠卡,就传入该优惠卡的标识即可;
2,该类依赖一个与一个价格策略的工厂接口,该类将通过该工厂接口动态的选择一个策略;
public class BookPriceHandler implements PriceHandler{ private IPriceStratedyFactory ipsf; public BookPriceHandler() { this(new PriceStrategyFactory()); } public BookPriceHandler(IPriceStratedyFactory ipsf) { this.ipsf = ipsf; } @Override public double calcPrice(double price, PricePrivilege pp) { //特权价格 price = privilegePrice(price, pp); //固定策略 price = ipsf.createAndGet(price).calcPrice(price); return price; } private double privilegePrice(double price , PricePrivilege pp) { if(pp == null) return price; return privilegePrice(pp.calcPrice(price), pp.next()); } }
demo:
public class Demo { public static void main(String[] args) { BookPriceHandler bphandler = new BookPriceHandler(); PricePrivilege pc = new PreferentialCar(); PricePrivilege b = new Birthday(); b.register(pc); double price = bphandler.calcPrice(500, b); System.out.println(price); } }
使用注意:请将策略类放置与PriceStrategyFactory $LoadPriceStrategyUtil.STRATEGY_URL所指定的包路径下,否则将抛出classnotfound 异常;
以上是关于工厂模式策略者模式责任链模式综合应用的主要内容,如果未能解决你的问题,请参考以下文章