策略模式和工厂模式搭配使用
策略模式和工廠模式的搭配使用可以很好地消除代碼
if-else的多層嵌套
需求
針對店下商鋪,有這樣一個需求,對用戶客戶分為了普通客戶、vip客戶、超級vip用戶、專屬vip用戶4個等級,每當用戶購買商品時,針對不同的用戶等級和消費金額采取不同的打折優(yōu)惠策略。在平常的開發(fā)當中,必然會出現(xiàn)多層的if-else嵌套判斷,先判斷用戶的等級再判斷用戶購買商品的消費金額。
弊端
以上的情況出現(xiàn)了多層的if-else嵌套,除此之外,以后如果需求再有變動,需要再增加一個用戶等級,那么又會再次添加if-else的嵌套判斷,那么如何解決上述的弊端呢,采用策略模式和工廠模式的搭配使用,可以很好地優(yōu)化多層if-else的多層嵌套
實現(xiàn)
編寫用戶等級枚舉類
package com.zbiti.ifelse.UserType;
/**
* 用戶類型枚舉類
*/
public enum UserPayServiceEnum {
VIP(1,"Vip"),
SUPERVIP(2,"SuperVip"),
PARTICULALYVIP(3,"ParticularlyVip"),
NORMAL(4,"NormalPayService");
/**
* 狀態(tài)值
*/
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());
}
}
編寫不同的用戶等級策略類
以下需要注意的是每個策略類實現(xiàn)了InitializingBean接口的作用是每當策略類被spring容器啟動初始化后會調(diào)用afterPropertiesSet方法,而在這個方法里面的作用是會往工廠里針對不同用戶等級保存其對應(yīng)的用戶策略引用
編寫打折接口
不同的用戶等級策略類實現(xiàn)該接口,該接口包含了打折方法
package com.zbiti.ifelse.UserType;
import java.math.BigDecimal;
public interface UserPayService {
/**
* 計算應(yīng)付價格
*/
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;
/**
* 普通會員不打折原價
*/
//實現(xiàn)InitializingBean接口,容器啟動后會調(diào)用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折
*/
//實現(xiàn)InitializingBean接口,容器啟動后會調(diào)用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即各個不同等級的用戶策略類完成后調(diào)用afterPropertiesSet方法里調(diào)用register方法,當容器啟動完成后,我們的spring容器中即有了一個鍵為用戶等級,值為用戶等級策略類的map,在對不同用戶進行優(yōu)惠打折的時候,可以根據(jù)用戶等級來取得當前用戶的策略類
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";
//指定用戶類型,獲得相對應(yīng)的策略
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);
}
}
結(jié)果
可以看到vip用戶打9折,在這個不同用戶等級購買商品時采取的不同打折策略里,我們沒有出現(xiàn)了多層的if-else的嵌套
tips
編寫工廠類的實現(xiàn)方式上面是其中一種實現(xiàn)(比較推薦),另外也有其它的方式,可以參考如下
提前將策略寫入到map,但是這里需要手動new策略對象
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中也是可以的。
參考
if-else
if-else2
if-else3
本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布!
總結(jié)
以上是生活随笔為你收集整理的策略模式和工厂模式搭配使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ug编程内公差和外公差是什么_干货丨模具
- 下一篇: ts可展开注释_Nike控告WL的始末,