工厂模式策略者模式责任链模式综合应用(代码片段)

loveyoumi loveyoumi     2022-12-28     756

关键词:

设计模式的具体运用:

  简单工厂模式、策略者模式、责任链模式定义与使用

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 异常;





kotlin-改良责任链模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言责任链模式作用:避免请... 查看详情

kotlin-改良责任链模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言责任链模式作用:避免请... 查看详情

设计模式之责任链模式(代码片段)

责任链模式1.简要概述2.模式结构3.实现代码4.优点好处5.缺点弊端6.应用场景7.应用示例1.简要概述责任链模式也叫作职责链模式,属于行为型设计模式。责任链模式将能够处理同一类请求的对象连成一条链,所提交的请求... 查看详情

设计模式

...剥茧策略模式 动态添加对象:ArrayListLinkedList 静态工厂方法责任链多态创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七种:适配器模式、装饰器模式、代理模式... 查看详情

kotlin-改良工厂模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言设计模式是软件工程中解决特... 查看详情

kotlin-改良策略模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言策略模式作用:让算法的... 查看详情

kotlin-改良策略模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言策略模式作用:让算法的... 查看详情

设计模式----责任链模式(代码片段)

责任链模式引言责任链模式定义类图角色核心示例代码1、对请求处理者的抽象2、对请求处理者的抽象3、责任链的创建责任链实现请假案例案例类图可扩展性纯与不纯的责任链模式纯的责任链模式不纯的责任链模式责任链模式主... 查看详情

设计模式10-策略模式与责任链模式详解(代码片段)

1.10.策略模式与责任链模式详解1.10.1.策略模式详解时长:1h15min10.1.1.策略模式的定义定义:  策略模式【Strategy Pattern】,又叫政策模式【PolicyPattern】,它是将定义的算法家族,分别封装起来,让它们之间可以相互替换,从而... 查看详情

kotlin-改良构建者模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言构建者模式作用:将一个... 查看详情

kotlin-改良构建者模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言构建者模式作用:将一个... 查看详情

kotlin-改良装饰者模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言装饰者模式作用:在不必... 查看详情

kotlin-改良装饰者模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言装饰者模式作用:在不必... 查看详情

设计模式之责任链模式(代码片段)

...要增加问题,每次都要增加if判断语句,将其改用责任链模式进行链式调用,为了让代码更加的优雅,我们使用之前学过的建造者模式就代码进行改造。接着我们会介绍责任链模式在我们常用的框架中的运用,最后是责任链模式... 查看详情

python常用的设计模式(代码片段)

...目录1.设计模式2.面向对象设计原则3.创建型模式3.1.简单工厂模式3.2.工厂方法模式3.3.抽象工厂模式3.4.建造者模式3.5.单例模式3.6.创建型模式概述4.结构型模式4.1.适配器模式4.2.桥模式4.3.组合模式4.4.外观模式4.5.代理模式5.行为型模... 查看详情

python设计模式—行为型模式—责任链模式(代码片段)

目录文章目录目录责任链模式应用场景代码示例责任链模式责任链模式,将多个处理方法连接成一条链条,请求将在这条链条上流动直到该链条中有一个节点可以处理该请求。通常这条链条是一个对象包含对另一个对象... 查看详情

设计模式-责任链模式(代码片段)

责任链(ChainofResponsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处... 查看详情

kotlin-改良责任链模式(代码片段)

欢迎关注微信公众号:FSA全栈行动👋Kotlin-改良工厂模式Kotlin-改良构建者模式Kotlin-改良观察者模式Kotlin-改良策略模式Kotlin-改良迭代器模式Kotlin-改良责任链模式Kotlin-改良装饰者模式一、前言责任链模式作用:避免请... 查看详情