策略模式和工廠模式的搭配使用能夠很好地消除代碼
if-else
的多層嵌套java
針對店下商鋪,有這樣一個需求,對用戶客戶分爲了普通客戶、vip
客戶、超級vip
用戶、專屬vip
用戶4
個等級,每當用戶購買商品時,針對不一樣的用戶等級和消費金額採起不一樣的打折優惠策略。在日常的開發當中,必然會出現多層的if-else
嵌套判斷,先判斷用戶的等級再判斷用戶購買商品的消費金額。spring
以上的狀況出現了多層的if-else
嵌套,除此以外,之後若是需求再有變更,須要再增長一個用戶等級,那麼又會再次添加if-else
的嵌套判斷,那麼如何解決上述的弊端呢,採用策略模式和工廠模式的搭配使用,能夠很好地優化多層if-else
的多層嵌套api
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
方法,而在這個方法裏面的做用是會往工廠裏針對不一樣用戶等級保存其對應的用戶策略引用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);
}
}
複製代碼
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);
}
}
複製代碼
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);
}
}
複製代碼
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);
}
}
複製代碼
結果this
能夠看到vip
用戶打9
折,在這個不一樣用戶等級購買商品時採起的不一樣打折策略裏,咱們沒有出現了多層的if-else
的嵌套spa
編寫工廠類的實現方式上面是其中一種實現(比較推薦),另外也有其它的方式,能夠參考以下.net
提早將策略寫入到map
,可是這裏須要手動new
策略對象code
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 發佈!