策略模式和工厂模式的搭配使用能够很好地消除代码
if-else
的多层嵌套html
需求
针对店下商铺,有这样一个需求,对用户客户分为了普通客户、vip
客户、超级vip
用户、专属vip
用户4
个等级,每当用户购买商品时,针对不一样的用户等级和消费金额采起不一样的打折优惠策略。在日常的开发当中,必然会出现多层的if-else
嵌套判断,先判断用户的等级再判断用户购买商品的消费金额。java
弊端
以上的状况出现了多层的if-else
嵌套,除此以外,之后若是需求再有变更,须要再增长一个用户等级,那么又会再次添加if-else
的嵌套判断,那么如何解决上述的弊端呢,采用策略模式和工厂模式的搭配使用,能够很好地优化多层if-else
的多层嵌套spring
实现
编写用户等级枚举类
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
方法,而在这个方法里面的做用是会往工厂里针对不一样用户等级保存其对应的用户策略引用api
编写打折接口
不一样的用户等级策略类实现该接口,该接口包含了打折方法ide
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<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); } }
编写测试类
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
的嵌套this
tips
编写工厂类的实现方式上面是其中一种实现(比较推荐),另外也有其它的方式,能够参考以下spa
提早将策略写入到map
,可是这里须要手动new
策略对象.net
package com.zbiti.ifelse.UserType; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 版本一:工厂使用 */ public class UserPayServiceStrategyFactory2 { private static Map<String,UserPayService> services = new ConcurrentHashMap<String,UserPayService>(); 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<String, Class<? extends UserPayService>> 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 发布!
原文出处:https://www.cnblogs.com/lisingshen/p/11782250.html