策略模式例項

Lz_蚂蚱發表於2024-03-18

目錄
  • 需求描述
  • 程式碼實現
    • 初始化容器配置
    • 廠商型別列舉
    • 策略來源註解
    • 廠商來源工廠配置
    • 初始化來源工廠配置
    • 業務程式碼

需求描述

購買手機分為三個手機廠商:華為手機、小米手機、OPPO手機,根據每個手機廠商編碼檢視對應廠商旗艦手機。

程式碼實現

初始化容器配置

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 初始化配置容器
 * 
 * @author leizi
 * @date 2024/03/17
 */
@Component
@Slf4j
public class AppContext implements ApplicationContextAware {

    private static ApplicationContext appContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (null == appContext) {
            if (null != applicationContext) {
                AppContext.appContext = applicationContext;
            }
            log.info("Spring init successfully");
        }

    }

    public static ApplicationContext getContext() {
        if (appContext == null) {
            throw new IllegalStateException("applicationContext inject failure,please restart the service");
        }
        return appContext;
    }
}

廠商型別列舉

/**
 * 手機廠商列舉
 *
 * @author leizi
 * @date 2024/03/17
 */
public enum SourceTypeEnum {

    HUAWEI(1, "華為廠商"),
    XIAOMI(2, "小米廠商"),
    OPPO(3, "OPPO廠商");

    private Integer type;

    private String memo;

    SourceTypeEnum(Integer type, String memo) {
        this.type = type;
        this.memo = memo;
    }

    public Integer getType() {
        return type;
    }

    public String getMemo() {
        return memo;
    }

    /**
     * 根據型別獲取例項
     *
     * @param type
     * @return
     */
    public static SourceTypeEnum getInstance(Integer type) {
        if (null == type) {
            return null;
        }
        for (SourceTypeEnum typeEnum : SourceTypeEnum.values()) {
            if (typeEnum.type.equals(type)) {
                return typeEnum;
            }
        }
        return null;
    }
}

策略來源註解

import com.example.demo.enums.SourceTypeEnum;
import org.springframework.stereotype.Component;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 廠商來源註解
 *
 * @author leizi
 * @date 2024/03/17
 */
@Inherited
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface SourceType {

    SourceTypeEnum value();

}

廠商來源工廠配置

/**
 * @author leizi
 * @date 2024/03/18
 */
public interface InitProcess {
    /**
     * 初始化工廠
     */
    void init();
}
import cn.hutool.core.map.MapUtil;
import com.example.demo.annotation.SourceType;
import com.example.demo.enums.SourceTypeEnum;
import com.example.demo.service.PhoneManufacturerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author leizi
 * @date 2024/03/17
 */
@Component
@Slf4j
public class FactoryHandlerStrategy implements InitProcess {

    private static ConcurrentHashMap<SourceTypeEnum, PhoneManufacturerService> phoneManufacturerMap = new ConcurrentHashMap<>();

    @Override
    public void init() {
        initPhoneManufacturer();
    }

    /**
     * 初始化phoneManufacturerMap
     */
    private void initPhoneManufacturer() {
        // 載入PhoneManufacturerService 廠商處理實現類
        Map<String, PhoneManufacturerService> mapPhoneManufacturer = AppContext.getContext().getBeansOfType(PhoneManufacturerService.class);
        mapPhoneManufacturer.entrySet().stream().forEach(entry -> {
            Class<? extends Object> clazz = entry.getValue().getClass();
            SourceType annotation = clazz.getAnnotation(SourceType.class);
            /*if (null == annotation) {
                // 這裡為處理方法使用@Async,SourceType型別獲取失效問題
                Map<String, Object> map = JSON.parseObject(JSON.toJSONString(entry.getValue()));
                Object decoratedClass = map.get("decoratedClass");
                try {
                    clazz = Class.forName(decoratedClass.toString());
                    annotation = clazz.getAnnotation(SourceType.class);
                } catch (Exception e) {
                    log.error("class forName error:{}", e);
                }
            }*/
            if (null == annotation) {
                return;
            }
            SourceTypeEnum sourceType = annotation.value();
            if (null != sourceType) {
                PhoneManufacturerService phoneManufacturerService = phoneManufacturerMap.get(sourceType);
                if (null != phoneManufacturerService) {
                    phoneManufacturerMap.remove(sourceType);
                }
                phoneManufacturerMap.put(sourceType, entry.getValue());
            }
        });
    }

    /**
     * 根據廠商來源獲取實現類
     *
     * @param sourceType
     * @return
     */
    public PhoneManufacturerService getPhoneManufacturer(SourceTypeEnum sourceType) {
        if (MapUtil.isEmpty(phoneManufacturerMap)) {
            initPhoneManufacturer();
        }
        return phoneManufacturerMap.get(sourceType);
    }


}

初始化來源工廠配置

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/**
 * 初始配置
 *
 * @author leizi
 * @date 2024/03/18
 */
@Component
public class InitContext implements ApplicationRunner {

    private final FactoryHandlerStrategy factoryHandlerStrategy;

    public InitContext(FactoryHandlerStrategy factoryHandlerStrategy) {
        this.factoryHandlerStrategy = factoryHandlerStrategy;
    }

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        /*
         * 容器啟動完成把實現InitProcess實現類都執行init初始化操作,根據實際需要實現
         * */
//        Map<String, InitProcess> processMap = AppContext.getContext().getBeansOfType(InitProcess.class);
        factoryHandlerStrategy.init();
    }
}

業務程式碼

/**
 * @author leizi
 * @date 2024/03/17
 */
public interface PhoneManufacturerService {

    /**
     * 根據廠商型別檢視手機
     *
     * @param type 廠商型別
     * @return
     */
    String getPhone(Integer type);

    /**
     * 購買指定廠商手機
     *
     * @param type 廠商型別
     * @return
     */
    String buyPhone(Integer type);

}
import com.example.demo.annotation.SourceType;
import com.example.demo.enums.SourceTypeEnum;
import com.example.demo.service.PhoneManufacturerService;

/**
 * OPPO廠商手機
 *
 * @author leizi
 * @date 2024/03/17
 */
@SourceType(SourceTypeEnum.OPPO)
public class OppoManufacturerServiceImpl implements PhoneManufacturerService {
    @Override
    public String getPhone(Integer type) {
        return "一臺OPPOFindX500旗艦手機";
    }

    @Override
    public String buyPhone(Integer type) {
        return "購買了OPPOFindX500旗艦手機";
    }
}
import com.example.demo.annotation.SourceType;
import com.example.demo.enums.SourceTypeEnum;
import com.example.demo.service.PhoneManufacturerService;

/**
 * 小米廠商手機
 *
 * @author leizi
 * @date 2024/03/17
 */
@SourceType(SourceTypeEnum.XIAOMI)
public class XiaomiManufacturerServiceImpl implements PhoneManufacturerService {
    @Override
    public String getPhone(Integer type) {
        return "一臺小米100pro旗艦手機";
    }

    @Override
    public String buyPhone(Integer type) {
        return "購買了小米100pro旗艦手機";
    }
}
import com.example.demo.annotation.SourceType;
import com.example.demo.enums.SourceTypeEnum;
import com.example.demo.service.PhoneManufacturerService;

/**
 * 華為廠商手機
 *
 * @author leizi
 * @date 2024/03/17
 */
@SourceType(SourceTypeEnum.HUAWEI)
public class HuaweiManufacturerServiceImpl implements PhoneManufacturerService {

    @Override
    public String getPhone(Integer type) {
        return "一臺華為Mete100旗艦手機";
    }

    @Override
    public String buyPhone(Integer type) {
        return "購買了華為Mete100旗艦手機";
    }
}
import com.example.demo.config.FactoryHandlerStrategy;
import com.example.demo.enums.SourceTypeEnum;
import com.example.demo.service.PhoneManufacturerService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author leizi
 * @date 2024/03/17
 */
@RestController
@RequestMapping("/phone")
public class PhoneController {

    private final FactoryHandlerStrategy factoryHandlerStrategy;

    public PhoneController(FactoryHandlerStrategy factoryHandlerStrategy) {
        this.factoryHandlerStrategy = factoryHandlerStrategy;
    }


    @GetMapping("/get")
    public String getPhone(@RequestParam Integer type) {

        PhoneManufacturerService manufacturerService = factoryHandlerStrategy.getPhoneManufacturer(SourceTypeEnum.getInstance(type));
        if (null != manufacturerService) {
            return manufacturerService.getPhone(type);
        }
        return "獲取失敗了";
    }

}

相關文章