策略模式和工厂模式的搭配使用可以很好地消除代码if-else的多层嵌套

需求

针对店下商铺,有这样一个需求,对用户客户分为了普通客户、vip客户、超级vip用户、专属vip用户4个等级,每当用户购买商品时,针对不同的用户等级和消费金额采取不同的打折优惠策略。在平常的开发当中,必然会出现多层的if-else嵌套判断,先判断用户的等级再判断用户购买商品的消费金额。

弊端

以上的情况出现了多层的if-else嵌套,除此之外,以后如果需求再有变动,需要再增加一个用户等级,那么又会再次添加if-else的嵌套判断,那么如何解决上述的弊端呢,采用策略模式和工厂模式的搭配使用,可以很好地优化多层if-else的多层嵌套

实现

编写用户等级枚举类

package com.zbiti.ifelse.UserType;

/**

* 用户类型枚举类

*/

public enum UserPayServiceEnum {

VIP(1,"Vip"),

SUPERVIP(2,"SuperVip"),

PARTICULALYVIP(3,"ParticularlyVip"),

NORMAL(4,"NormalPayService");

/**

* 状态值

*/

private int code;

/**

* 类型描述

*/

private String value;

private UserPayServiceEnum(int code, String value) {

this.code = code;

this.value = value;

}

public int getCode() {

return code;

}

public String getValue() {

return value;

}

public static UserPayServiceEnum valueOf(int code) {

for (UserPayServiceEnum type : UserPayServiceEnum.values()) {

if (type.getCode()==code) {

return type;

}

}

return null;

}

public static void main(String[] args) {

System.out.println(UserPayServiceEnum.VIP.getValue());

}

}

编写不同的用户等级策略类

以下需要注意的是每个策略类实现了InitializingBean接口的作用是每当策略类被spring容器启动初始化后会调用afterPropertiesSet方法,而在这个方法里面的作用是会往工厂里针对不同用户等级保存其对应的用户策略引用

编写打折接口

不同的用户等级策略类实现该接口,该接口包含了打折方法

package com.zbiti.ifelse.UserType;

import java.math.BigDecimal;

public interface UserPayService {

/**

* 计算应付价格

*/

public BigDecimal quote(BigDecimal orderPrice);

}

编写普通用户策略类

package com.zbiti.ifelse.UserType;

import org.springframework.beans.factory.InitializingBean;

import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**

* 普通会员不打折原价

*/

//实现InitializingBean接口,容器启动后会调用afterPropertiesSet()方法,往工厂里写入打折策略

@Service

public class NormalPayService implements UserPayService, InitializingBean {

@Override

public BigDecimal quote(BigDecimal orderPrice) {

return new BigDecimal("10");

}

@Override

public void afterPropertiesSet() throws Exception {

UserPayServiceStrategyFactory.register(UserPayServiceEnum.NORMAL.getValue(), this);

}

}

编写vip用户策略类

package com.zbiti.ifelse.UserType;

import org.springframework.beans.factory.InitializingBean;

import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**

* 普通会员打9折,消费超100打8折

*/

//实现InitializingBean接口,容器启动后会调用afterPropertiesSet()方法,往工厂里写入打折策略

@Service

public class VipPayService implements UserPayService, InitializingBean {

@Override

public BigDecimal quote(BigDecimal orderPrice) {

if (orderPrice.compareTo(new BigDecimal("100")) > 1) {

return new BigDecimal("8");

}

return new BigDecimal("9");

}

public void myShow(){

System.out.println("myShow method invoke----->");

}

@Override

public void afterPropertiesSet() throws Exception {

UserPayServiceStrategyFactory.register(UserPayServiceEnum.VIP.getValue(), this);

}

}

编写超级vip用户策略类

package com.zbiti.ifelse.UserType;

import org.springframework.beans.factory.InitializingBean;

import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**

* 超级会员打8折

*/

@Service

public class SuperVipPayService implements UserPayService , InitializingBean {

@Override

public BigDecimal quote(BigDecimal orderPrice) {

return new BigDecimal("8");

}

@Override

public void afterPropertiesSet() throws Exception {

UserPayServiceStrategyFactory.register(UserPayServiceEnum.SUPERVIP.getValue(),this);

}

}

编写专属用户vip策略类

package com.zbiti.ifelse.UserType;

import org.springframework.beans.factory.InitializingBean;

import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**

* 专属会员 下单消费超30打七折

*/

@Service

public class ParticularlyVipPayService implements UserPayService, InitializingBean {

@Override

public BigDecimal quote(BigDecimal orderPrice) {

if (orderPrice.compareTo(new BigDecimal("30"))>0) {

return new BigDecimal("7");

}

return new BigDecimal("8");

}

@Override

public void afterPropertiesSet() throws Exception {

UserPayServiceStrategyFactory.register(UserPayServiceEnum.PARTICULALYVIP.getValue(),this);

}

}

编写工厂类

注意这里工厂的register方法,该方法会在spring容器启动初始化bean即各个不同等级的用户策略类完成后调用afterPropertiesSet方法里调用register方法,当容器启动完成后,我们的spring容器中即有了一个键为用户等级,值为用户等级策略类的map,在对不同用户进行优惠打折的时候,可以根据用户等级来取得当前用户的策略类

package com.zbiti.ifelse.UserType;

import org.springframework.util.Assert;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

/**

* 版本二:工厂使用(高级版)

*/

//@Service

public class UserPayServiceStrategyFactory {

private static Map services = new ConcurrentHashMap();

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);

}

}

编写测试类

package com.zbiti.ifelse;

import com.zbiti.ifelse.UserType.UserPayService;

import com.zbiti.ifelse.UserType.UserPayServiceStrategyFactory;

import com.zbiti.ifelse.UserType.VipPayService;

import lombok.extern.slf4j.Slf4j;

import org.junit.jupiter.api.Test;

import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;

@SpringBootTest

@Slf4j

class IfElseApplicationTests {

@Test

void contextLoads() {

calPrice();

}

public void calPrice() {

BigDecimal orderPrice = new BigDecimal("100");

String vipType = "Vip";

//指定用户类型,获得相对应的策略

UserPayService strategy = UserPayServiceStrategyFactory.getByUserType(vipType);

// UserPayService strategy2 = UserPayServiceStrategyFactory2.getByUserType(vipType);

System.out.println(strategy);

// System.out.println(strategy2);

BigDecimal quote = strategy.quote(orderPrice);

if(strategy instanceof VipPayService){

((VipPayService) strategy).myShow();

}

System.out.println(quote);

}

}

结果

可以看到vip用户打9折,在这个不同用户等级购买商品时采取的不同打折策略里,我们没有出现了多层的if-else的嵌套

tips

编写工厂类的实现方式上面是其中一种实现(比较推荐),另外也有其它的方式,可以参考如下

提前将策略写入到map,但是这里需要手动new策略对象

package com.zbiti.ifelse.UserType;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

/**

* 版本一:工厂使用

*/

public class UserPayServiceStrategyFactory2 {

private static Map services = new ConcurrentHashMap();

public static UserPayService getByUserType(String type){

return services.get(type);

}

static{

services.put(UserPayServiceEnum.VIP.getValue(), new VipPayService());

services.put(UserPayServiceEnum.SUPERVIP.getValue(), new SuperVipPayService());

services.put(UserPayServiceEnum.PARTICULALYVIP.getValue(), new ParticularlyVipPayService());

services.put(UserPayServiceEnum.NORMAL.getValue(), new NormalPayService());

}

}

也可以通过反射,编写工厂类

package com.zbiti.ifelse.UserType;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

/**

* 版本一:工厂使用

*/

public class UserPayServiceStrategyFactory3 {

private static Map> services = new ConcurrentHashMap<>();

//初始化map,存放策略

static {

services.put(UserPayServiceEnum.VIP.getValue(), VipPayService.class);

services.put(UserPayServiceEnum.SUPERVIP.getValue(), SuperVipPayService.class);

services.put(UserPayServiceEnum.PARTICULALYVIP.getValue(), ParticularlyVipPayService.class);

services.put(UserPayServiceEnum.NORMAL.getValue(), NormalPayService.class);

}

//获取策略

public static UserPayService getByUserType(String type) {

try {

Class extends UserPayService> userPayServiceClass = services.get(type);

return userPayServiceClass.newInstance();

} catch (Exception e) {

e.printStackTrace();

return new NormalPayService();

}

}

}

其实也可以搭配注解的使用,自定义一个注解类,在策略类上标识上注解(值为不同的用户等级),容器启动的时候通过扫描我们的自定义注解,写入map中也是可以的。

参考

本文由博客一文多发平台 OpenWrite 发布!

java策略模式 工厂模式_策略模式和工厂模式搭配使用相关推荐

  1. 策略模式示例代码_策略设计模式示例

    策略模式示例代码 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如此重要的 ...

  2. java 工厂模式的写法_设计模式-Java-简单工厂模式--BitmapFactory

    上一篇,我们说了下MonkeyLei:设计模式-Java-观察者模式-RxJava 其中还利用到了反射的知识,另外也附上了很多我觉得分析还可以的链接. 这里我们看看简单工厂这块.除了这个还有其他几个: ...

  3. java 如何循环执行一个对象_养猪场循环生态循环模式及其效益分析,当前牧草成为生态循环猪场效益更好的选择,如何打造一个现代生态循环的高效益猪场?...

    养猪场循环生态循环模式及其效益分析 2010年前的推广模式参考 随着国民经济的快速发展,人民的生活水平在不断提高,民众对环境的要求也越来越高,包括人文环境和自然环境.同时,农村地区的环境治理工作也逐渐 ...

  4. 苹果手机夜间模式怎么设置_微信怎么设置夜间模式?iPhone夜间模式设置教程 省电又护眼!...

    最近有小伙伴后台留言问了这样一个问题,微信怎么设置夜间模式?首先微信APP目前本身并没有加入夜间模式,如果觉得夜间看手机刺眼的话,可以开启手机自动的夜间模式,大多数安卓和iOS手机都支持,开启后不仅更 ...

  5. java迭代器的使用场景_集合遍历利器 -- 迭代器模式 介绍 使用场景案例 优缺点及程序演示...

    一句话概括: 顺序访问集合对象的元素,不需要知道集合对象的底层表示. 补充介绍: 迭代器模式(Iterator Pattern)相信大家都已经见过不少次了,当你学习Java或者其他编程语言的开始你就会 ...

  6. java语言描述一个行为_设计模式之责任链模式——Java语言描述

    责任链模式为请求创建了一个接受者对象的链.这种模式给予请求的类型,对请求的发送者和接受者进行解耦.这种类型的设计模式属于行为模式.在这种模式下,通常每个接收者都包含对另一个接收者的引用.如果一个对象不 ...

  7. java ftp主动模式和被动模式_什么是ftp主动模式和被动模式

    FTP是文件传输协议的简称,ftp传输协议有着众多的优点所以传输文件时使用ftp协议的软件很多,ftp协议使用的端口是21(也称为控制端口),其实还有一个数据端口20,根据FTP工作方式的不同,数据端 ...

  8. java我的世界极限生存_我的世界极限生存模式攻略 极限生存心得

    我的世界minecraft中的极限模式可能会成为你所玩过的最难的游戏.请小心,一旦死亡,你将无法重生,即从磁盘上删除这个存档.(在极为罕见的情况下,可能不会从你的硬盘上删除,但是在重新打开时会弹出提示 ...

  9. java 9宫格抽奖_前端js实现九宫格模式抽奖(多宫格抽奖)

    介绍: 前端九宫格是一种常见的抽奖方式,js实现如下,掌握其原理,不论多少宫格,都可以轻松应对.(代码可复制直接运行看效果). 该案例以四宫格入门,可扩展多宫格,奖品模块的布局可自由设置. 四宫格抽奖 ...

  10. 在python语言中ipo模式不包括_下面不是IPO模式的一部分的是()_学小易找答案

    [单选题]对于某个导体电阻的大小,以下说法正确的是 (6.0分) [单选题]下面不是IPO模式的一部分的是() [单选题]对如图 所示的电路,下列说法正确的是 (6.0分) [填空题]Python语言 ...

最新文章

  1. Virtual Lab. For Probability and Statistics
  2. AIX samba服务器配置
  3. 华为的JAVA面试题及答案(部分)
  4. 鸿蒙手机(真机)播放音乐-第二集
  5. vue-cli 使用Mint-UI
  6. 车间调度建模系列1|复杂车间调度问题特点
  7. ADODB.Connection、ADODB.RecordSet
  8. mysql 嵌套查询
  9. 微信云控的大触来一下
  10. 安全学习木马查杀打卡第二十一天
  11. HDU4565 So Easy!【矩阵快速幂】
  12. Tushare财经数据调取方法(行情数据)
  13. Spark写入Hudi报分区列乱码问题java.net.URISyntaxException: Illegal character in path at index 46:
  14. Android Recovery OTA升级(二)—— Recovery源码解析
  15. 生于80年代,穷于10年代,败于90后
  16. JAVA中简单图形界面的创建
  17. 走近“领域特定语言”(Domain-Specific Languages)
  18. 【论文泛读62】HybridQA:通过表格和文本数据进行多跳问答的数据集
  19. 小本生意,请各位博友多多支持
  20. 南邮四年来的学校主页

热门文章

  1. 关于stack 和heap
  2. linux shell 读取for循环中出现难处理的数据之单引号错误实例
  3. LINUX让环境变量立即生效的方法
  4. java canvas 动态画图_canvas前端动图如何实现
  5. ie ajax异步缓存,IE下发送Ajax请求的缓存问题
  6. java this.val$_[Java教程]Jquery $(this).attr和$(this).val用法示例
  7. mysql盲注ascii_[翻译]关于通过对8bit的ascii做右位移提高mysql盲注效率
  8. 量子计算机迷宫,工程杰作诞生可编程的光学量子计算机
  9. excel运行python_使用PyXLL在Excel中执行Python脚本
  10. vscode括号颜色插件_[VSCode插件推荐] Bracket Pair Colorizer: 为代码中的括号添上一抹亮色...