策略模式和工廠模式搭配使用

策略模式和工廠模式的搭配使用能夠很好地消除代碼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中也是能夠的。

參考

if-else

if-else2

if-else3

本文由博客一文多發平臺 OpenWrite 發佈!

原文出處:https://www.cnblogs.com/lisingshen/p/11782250.html

相關文章
相關標籤/搜索