工厂模式和策略模式的综合使用

目录

一、简单的工厂模式了解与使用

(一)基本概念理解

(二)简单工厂模式的认识和对应角色的分析

基本认识

角色理解

(三)使用场景和典型应用

二、简单的策略模式了解与使用

(一)基本概念理解

(二)策略模式认识和对应角色的分析

基本认识

角色理解

(三)使用场景和典型应用

三、工厂模式和策略模式的综合使用

(一)应用背景介绍

(二)设计策略类

1.定义一个计算应付价格接口

2.用户是专属会员对应策略类

3.用户是超级会员对应策略类

4.用户是普通会员对应策略类

(三)设计对应的简单工厂模式

(四)知识补充:Spring Bean的注册

(五)具体实现应用测试如下

1.具体测试代码

2.对应结果展示

参考书籍、文献和资料


其实在很多的开发设计中,将工厂模式和策略模式的综合使用的案例是很多的,而且解决的实际问题也一样很多,本次对基本的简单工厂模式和策略模式做简单介绍,重点放在两者结合后的具体应用上做分析和讲解。

一、简单的工厂模式了解与使用

(一)基本概念理解

建立一个工厂,能轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程,这就是简单工厂的主要功能。

比方如下图:客户需要一辆宝马,具体的简单工厂会根据用户的实际需求去生产对应型号的宝马,最后返回客户需要的宝马产品。

(二)简单工厂模式的认识和对应角色的分析

基本认识

简单工厂模式(Simple Factory Pattern)需要定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式,但不属于GOF23种设计模式。

角色理解

  • Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product
  • Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
  • ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法

在简单工厂模式中,客户端通过工厂类来创建一个产品类的实例,而无须直接使用new关键字来创建对象,它是工厂模式家族中最简单的一员。

(三)使用场景和典型应用

  • 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
  • 典型应用:Calendar 类获取日历类对象、JDBC 获取数据库连接、Logback 中的 LoggerFactory 获取 Logger 对象

二、简单的策略模式了解与使用

(一)基本概念理解

主要指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。

在实际的代码中,外卖平台上的某家店铺为了促销,设置了多种会员优惠,其中包含超级会员折扣8折、普通会员折扣9折和普通用户没有折扣三种,也就是针对不同的会员有不同的优惠力度。

(二)策略模式认识和对应角色的分析

基本认识

策略模式是行为模式之一,它对一系列的算法加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定(策略)。Strategy 模式主要用来平滑地处理算法的切换。

角色理解

  • Strategy : 策略(算法)抽象。
  • ConcreteStrategy :各种策略(算法) 的具体实现
  • Contenxt :策略的外部封装类,或者说策略的容器类。根据不同策略执行不同的行为,策略由外部环境决定。

(三)使用场景和典型应用

  • 策略模式的等级结构定义了一个算法或行为族,恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
  • 策略模式提供了可以替换继承关系的办法。
  • 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护。它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起。统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。

三、工厂模式和策略模式的综合使用

(一)应用背景介绍

假设我们要做一个外卖平台,有这样的需求:

  • 外卖平台上的某家店铺为了促销,设置了多种会员优惠,其中包含超级会员折扣8折、普通会员折扣9折和普通用户没有折扣三种。
  • 希望用户在付款的时候,根据用户的会员等级,就可以知道用户符合哪种折扣策略,进而进行打折,计算出应付金额。
  • 随着业务发展,新的需求要求专属会员要在店铺下单金额大于30元的时候才可以享受优惠。
  • 接着,又有一个变态的需求,如果用户的超级会员已经到期了,并且到期时间在一周内,那么就对用户的单笔订单按照超级会员进行折扣,并在收银台进行强提醒,引导用户再次开通会员,而且折扣只进行一次。

(二)设计策略类

根据要求,用户具有会员等级,对应的会员等级在付款的时候享受对应的折扣策略,而后面是具体业务在不同变动时新增的内容,可以在具体的策略中去单独操作或在外围确定用户身份后进行基本的处理。

总之,从基本操作上来看,付款的行为是必然存在的,不同的用户在对应不同的变动下支付的具体策略有所不同,所以,可以确定一个基本的接口来表达具体要付款的行为,不同用户对具体等级的实现策略放在对应的实现类中做处理:

1.定义一个计算应付价格接口

/**
 * @author yanfengzhang
 */
public interface UserPayService {

    /**
     * 功能描述:计算应付价格
     * @author yanfengzhang
     * @date 2019-12-31 18:09
     * @param orderPrice BigDecimal
     * @return BigDecimal
    */
    BigDecimal quote(BigDecimal orderPrice);
}

2.用户是专属会员对应策略类

/**
 * 描述:用户是专属会员---订单金额大于30元,7折价格/否则9折价格
 *
 * @author yanfengzhang
 * @date 2019-12-31 18:11
 */
@Service
public class ParticularlyVipPayServiceImpl implements UserPayService, InitializingBean {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) {
        int payPrice = orderPrice.intValue();
        if (payPrice > 30) {
            return new BigDecimal(payPrice * 0.7);
        }
        return new BigDecimal(payPrice * 0.9);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        UserPayServiceStrategyFactory.register("ParticularlyVip", this);
    }
}

3.用户是超级会员对应策略类

/**
 * 描述:用户是超级会员---8折价格
 *
 * @author yanfengzhang
 * @date 2019-12-31 18:13
 */
@Service
public class SuperVipPayServiceImpl implements UserPayService , InitializingBean {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) {
        int payPrice = orderPrice.intValue();
        return new BigDecimal(payPrice * 0.8);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        UserPayServiceStrategyFactory.register("SuperVip",this);
    }
}

4.用户是普通会员对应策略类

/**
 * 描述:用户是普通会员
 * 情况1:该用户超级会员刚过期并且尚未使用过临时折扣-->临时折扣使用次数更新-->8折价格
 * 情况2:非以上情况-->9折价格
 *
 * @author yanfengzhang
 * @date 2019-12-31 18:15
 */
@Service
public class VipPayServiceImpl implements UserPayService, InitializingBean {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) {
        int payPrice = orderPrice.intValue();
        /*该用户超级会员刚过期并且尚未使用过临时折扣*/
        if (conditions()) {
            /*临时折扣使用次数更新*/
            updateSomething();
            return new BigDecimal(payPrice * 0.8);
        }
        return new BigDecimal(payPrice * 0.9);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        UserPayServiceStrategyFactory.register("Vip", this);
    }

    /**
     * 功能描述:满足一定的条件
     *
     * @author yanfengzhang
     * @date 2020-01-02 09:11
     */
    private boolean conditions() {
        return true;
    }

    private void updateSomething() {

    }
}

(三)设计对应的简单工厂模式

为了方便我们从Spring中获取UserPayService的各个策略类,我们创建一个工厂类来实现针对不同的用户实现对应的支付策略,具体如下:

/**
 * 描述:获取UserPayService的各个策略类
 * UserPayServiceStrategyFactory中定义了一个Map,用来保存所有的策略类的实例,并提供一个getByUserType方法,可以根据类型直接获取对应的类的实例。
 *
 * @author yanfengzhang
 * @date 2019-12-31 18:28
 */
public class UserPayServiceStrategyFactory {
    private static Map<String, UserPayService> services = new ConcurrentHashMap<String,UserPayService>();

    public  static UserPayService getByUserType(String type){
        return services.get(type);
    }

    public static void register(String userType,UserPayService userPayService){
        Assert.notNull(userType,"userType can't be null");
        services.put(userType,userPayService);
    }
}

(四)知识补充:Spring Bean的注册

UserPayServiceStrategyFactory提供了register方法,用来注册策略服务的。各个策略类调用register方法,把Spring通过IOC创建出来的Bean注册进去就行了。这种需求,可以借用Spring种提供的InitializingBean接口,这个接口为Bean提供了属性初始化后的处理方法,它只包括afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。

只需要每一个策略服务的实现类都实现InitializingBean接口,并实现其afterPropertiesSet方法,在这个方法中调用UserPayServiceStrategyFactory.register即可。

这样,在Spring初始化的时候,当创建VipPayService、SuperVipPayService和ParticularlyVipPayService的时候,会在Bean的属性初始化之后,把这个Bean注册到UserPayServiceStrategyFactory中。

(五)具体实现应用测试如下

1.具体测试代码

/**
 * 描述:通过策略模式、工厂模式以及Spring的InitializingBean,提升了代码的可读性以及可维护性,彻底消灭了一坨if-else
 * 注:1.这里使用的并不是严格意义上面的策略模式和工厂模式。
 *
 * @author yanfengzhang
 * @date 2019-12-31 18:21
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ZYFApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DeleteIfElseSkill {
    @Test
    public void testDeleteIfElseSkill() {
        User user1 = new User();
        user1.setVipType("ParticularlyVip");
        user1.setOrderPrice(new BigDecimal("100"));

        User user2 = new User();
        user2.setVipType("SuperVip");
        user2.setOrderPrice(new BigDecimal("100"));

        User user3 = new User();
        user3.setVipType("Vip");
        user3.setOrderPrice(new BigDecimal("100"));


        BigDecimal payPrice1 = UserPayServiceStrategyFactory.getByUserType(user1.getVipType()).quote(user1.getOrderPrice());
        System.out.println("用户为专属会员,并且订单金额为50,按会员优惠最后应支付:" + payPrice1);

        BigDecimal payPrice2 = UserPayServiceStrategyFactory.getByUserType(user2.getVipType()).quote(user2.getOrderPrice());
        System.out.println("用户为超级会员,并且订单金额为50,按会员优惠最后应支付:" + payPrice2);

        BigDecimal payPrice3 = UserPayServiceStrategyFactory.getByUserType(user3.getVipType()).quote(user3.getOrderPrice());
        System.out.println("用户为普通会员,并且订单金额为50,按会员优惠最后应支付:" + payPrice3);
    }

    @Data
    private static class User {
        private String uid;
        private String vipType;
        private BigDecimal orderPrice;
    }
}

2.对应结果展示

用户为专属会员,并且订单金额为50,按会员优惠最后应支付:70
用户为超级会员,并且订单金额为50,按会员优惠最后应支付:80
用户为普通会员,并且订单金额为50,按会员优惠最后应支付:80

 

参考书籍、文献和资料

1.https://blog.csdn.net/jason0539/article/details/23020989

2.https://blog.csdn.net/wwwdc1012/article/details/82504040

3.https://blog.csdn.net/lzb348110175/article/details/91633620

4.https://blog.csdn.net/Crazy_Cw/article/details/106818217

5.https://mp.weixin.qq.com/s/RG-h7r69JyKUlBZylJJIFQ

 

 

已标记关键词 清除标记
相关推荐
目录 第1章UML类图实训 1.1知识讲解 1.1.1UML概述 1.1.2类与类的UML表示 1.1.3类之间的关系 1.2实训实例 1.2.1类图实例之图书管理系统 1.2.2类图实例之商场会员管理系统 1.3实训练习 第2章面向对象设计原则实训 2.1知识讲解 2.1.1面向对象设计原则概述 2.1.2单一职责原则 2.1.3开闭原则 2.1.4里氏代换原则 2.1.5依赖倒转原则 2.1.6接口隔离原则 2.1.7合成复用原则 2.1.8迪米特法则 2.2实训实例 2.2.1单一职责原则实例分析 2.2.2开闭原则实例分析 2.2.3里氏代换原则实例分析 2.2.4依赖倒转原则实例分析 2.2.5接口隔离原则实例分析 2.2.6合成复用原则实例分析 2.2.7迪米特法则实例分析 2.3实训练习 第3章创建型模式实训 3.1知识讲解 3.1.1设计模式 3.1.2创建型模式概述 3.1.3简单工厂模式 3.1.4工厂方法模式 3.1.5抽象工厂模式 3.1.6建造者模式 3.1.7原型模式 3.1.8单例模式 3.2实训实例 3.2.1简单工厂模式实例之图形工厂 3.2.2工厂方法模式实例之日志记录器 3.2.3抽象工厂模式实例之数据库操作工厂 3.2.4建造者模式实例之游戏人物角色 3.2.5原型模式实例之快速创建工作周报 3.2.6单例模式实例之多文档窗口 3.3实训练习 第4章结构型模式实训 4.1知识讲解 4.1.1结构型模式概述 4.1.2适配器模式 4.1.3桥接模式 4.1.4组合模式 4.1.5装饰模式 4.1.6外观模式 4.1.7享元模式 4.1.8代理模式 4.2实训实例 4.2.1适配器模式实例之算法适配 4.2.2桥接模式实例之跨平台视频播放器 4.2.3组合模式实例之杀毒软件 4.2.4装饰模式实例之界面显示构件库 4.2.5外观模式实例之文件加密 4.2.6享元模式实例之围棋棋子 4.2.7代理模式实例之日志记录代理 4.3实训练习 第5章行为型模式实训 5.1知识讲解 5.1.1行为型模式概述 5.1.2职责链模式 5.1.3命令模式 5.1.4解释器模式 5.1.5迭代器模式 5.1.6中介者模式 5.1.7备忘录模式 5.1.8观察者模式 5.1.9状态模式 5.1.10策略模式 5.1.11模板方法模式 5.1.12访问者模式 5.2实训实例 5.2.1职责链模式实例之在线文档帮助系统 5.2.2命令模式实例之公告板系统 5.2.3解释器模式实例之机器人控制程序 5.2.4迭代器模式实例之商品名称遍历 5.2.5中介者模式实例之温度转换器 5.2.6备忘录模式实例之游戏恢复点设置 5.2.7观察者模式实例之股票变化 5.2.8状态模式实例之银行账户 5.2.9策略模式实例之电影票打折 5.2.10模板方法模式实例之数据库操作 5.2.11访问者模式实例之奖励审批 5.3实训练习 第6章模式联用与综合实例实训 6.1设计模式补充知识 6.1.1反射与配置文件 6.1.2GRASP模式 6.1.3架构模式与MVC 6.2模式联用实训 6.2.1适配器模式与桥接模式联用 6.2.2组合模式与命令模式联用 6.2.3外观模式与单例模式联用 6.2.4原型模式与备忘录模式联用 6.2.5观察者模式与组合模式联用 6.2.6访问者模式、组合模式与迭代器模式联用 6.3综合实例实训 6.3.1多人联机射击游戏 6.3.2数据库同步系统 6.4实训练习 附录A参考答案 A.1第1章实训练习参考答案 A.2第2章实训练习参考答案 A.3第3章实训练习参考答案 A.4第4章实训练习参考答案 A.5第5章实训练习参考答案 A.6第6章实训练习参考答案 参考文献
主要是介绍各种格式流行的软件设计模式,对于程序员的进一步提升起推进作用,有时间可以随便翻翻~~ 23种设计模式汇集 如果你还不了解设计模式是什么的话? 那就先看设计模式引言 ! 学习 GoF 设计模式的重要性 建筑和软件中模式之异同 A. 创建模式 设计模式之 Singleton(单态/单件) 阎宏博士讲解:单例(Singleton)模式 保证一个类只有一个实例,并提供一个访问它的全局访问点 设计模式之 Factory(工厂方法和抽象工厂) 使用工厂模式就象使用 new 一样频繁. 设计模式之 Builder 汽车由车轮 方向盘 发动机很多部件组成,同时,将这些部件组装成汽车也是一件复杂的工作,Builder 模式就是将这两 种情况分开进行。 设计模式之 Prototype(原型) 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 B. 结构模式 设计模式之 Adapter(适配器) 使用类再生的两个方式:组合(new)和继承(extends),这个已经在 thinking in java中提到过. 设计模式之 Proxy(代理) 以 Jive 为例,剖析代理模式在用户级别授权机制上的应用 设计模式之 Facade(门面?) 可扩展的使用 JDBC针对不同的数据库编程,Facade提供了一种灵活的实现. 设计模式之 Composite(组合) 就是将类用树形结构组合成一个单位.你向别人介绍你是某单位,你是单位中的一个元素,别人和你做买卖,相当于 和单位做买卖。文章中还对 Jive再进行了剖析。 设计模式之 Decorator(装饰器) Decorator 是个油漆工,给你的东东的外表刷上美丽的颜色. 设计模式之 Bridge(桥连) 将牛郎织女分开(本应在一起,分开他们,形成两个接口),在他们之间搭建一个桥(动态的结合) 设计模式之 Flyweight(共享元) 提供 Java运行性能,降低小而大量重复的类的开销. C. 行为模式 设计模式之 Command(命令) 什么是将行为封装,Command 是最好的说明. 设计模式之 Observer(观察者) 介绍如何使用 Java API 提供的现成 Observer 设计模式之 Iterator(迭代器) 这个模式已经被整合入Java的Collection.在大多数场合下无需自己制造一个Iterator,只要将对象装入Collection中, 直接使用 Iterator 进行对象遍历。 设计模式之 Template(模板方法) 实际上向你介绍了为什么要使用 Java 抽象类,该模式原理简单,使用很普遍. 设计模式之 Strategy(策略) 不同算法各自封装,用户端可随意挑选需要的算法. 设计模式之 Chain of Responsibility(责任链) 各司其职的类串成一串,好象击鼓传花,当然如果自己能完成,就不要推委给下一个. 设计模式之 Mediator(中介) Mediator 很象十字路口的红绿灯,每个车辆只需和红绿灯交互就可以. 设计模式之 State(状态) 状态是编程中经常碰到的实例,将状态对象化,设立状态变换器,便可在状态中轻松切换. 设计模式之 Memento(注释状态?) 很简单一个模式,就是在内存中保留原来数据的拷贝. 设计模式之 Interpreter(解释器) 主要用来对语言的分析,应用机会不多. 设计模式之 Visitor(访问者) 访问者在进行访问时,完成一系列实质性操作,而且还可以扩展. 设计模式引言 设计面向对象软件比较困难,而设计可复用的面向对象软件就更加困难。你必须找到相关的对象,以适当的粒度将它们归 类,再定义类的接口和继承层次,建立对象之间的基本关系。你的设计应该对手头的问题有针对性,同时对将来的问题和需求 也要有足够的通用性。 你也希望避免重复设计或尽可能少做重复设计。有经验的面向对象设计者会告诉你,要一下子就得到复用性和灵活性好的设计, 即使不是不可能的至少也是非常困难的。一个设计在最终完成之前常要被复用好几次,而且每一次都有所修改。 有经验的面向对象设计者的确能做出良好的设计,而新手则面对众多选择无从下手,总是求助于以前使用过的非面向对象 技术。新手需要花费较长时间领会良好的面向对象设计是怎么回事。有经验的设计者显然知道一些新手所不知道的东西,这又 是什么呢? 内行的设计者知道:不是解决任何问题都要从头做起。他们更愿意复用以前使用过的解决方案。当找到一个好的解决方案,他 们会一遍又一遍地使用。这些经验是他们成为内行的部分原因。因此,你会在许多面向对象系统中看到类和相互通信的对象( c o m
©️2020 CSDN 皮肤主题: 点我我会动 设计师:白松林 返回首页