Spring優(yōu)雅的實(shí)現(xiàn)策略模式

源碼

https://github.com/shawntime/shawn-design-pattern/

定義

定義了一些平行的算法組,分別封裝起來,算法之間可以相互替換,此模式使算法的變化獨(dú)立于調(diào)用者之外

算法結(jié)構(gòu)

  • 抽象策略角色(Strategy):這是一個(gè)抽象類或者接口,將算法的行為進(jìn)行封裝,所有的策略類都要實(shí)現(xiàn)該接口
  • 具體策略角色(ConcreteStrategy):封裝了具體的算法和行為
  • 環(huán)境角色(Context):持有一個(gè)抽象策略的引用,并提供統(tǒng)一調(diào)用的入口

結(jié)構(gòu)代碼

package com.shawntime.designpattern.strategy.demo;

/**
 * 抽象策略類
 */
public interface Strategy {

    // 策略方法
    void strategyInterface();
}

package com.shawntime.designpattern.strategy.demo;

/**
 * Created by shma on 2018/9/26.
 */
public class ConcreteStrategyA implements Strategy {

    public void strategyInterface() {
        // A相關(guān)業(yè)務(wù)
    }
}

package com.shawntime.designpattern.strategy.demo;

/**
 * Created by shma on 2018/9/26.
 */
public class ConcreteStrategyB implements Strategy {

    public void strategyInterface() {
        // B相關(guān)業(yè)務(wù)
    }
}

package com.shawntime.designpattern.strategy.demo;

/**
 * 環(huán)境角色類
 */
public class Context {

    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    // 對(duì)外暴露的策略方法
    public void contextInterface() {
        strategy.strategyInterface();
    }

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
}

項(xiàng)目實(shí)例

背景

在項(xiàng)目中,根據(jù)專題id去獲得該專題下活動(dòng)的禮品信息, 由于每個(gè)類型活動(dòng)禮品的方式不同,相互之間沒有關(guān)聯(lián),屬于平級(jí)的行為,因而采用策略模式。

方案1:通過spring配置注入策略
public interface IGiftInfoStrategyService {

    GiftInfo getGiftInfo(int activityId);
    int typeId();
}

/**
 * 夏季購車節(jié)
 */
@Service
public class SummerBuyDayGiftInfoStrategyService implements IGiftInfoStrategyService {

    @Resource
    private GiftInfoMapper giftInfoMapper;
    
    public GiftInfo getGiftInfo(int activityId) {
        // 從數(shù)據(jù)庫中查詢
        GiftInfo giftInfo = new GiftInfo();
        giftInfo.setGiftId(1);
        giftInfo.setGiftName("鐵鍋三件套");
        giftInfoMapper.getGiftInfoByActivityId(activityId)
        return giftInfo;
    }

    @Override
    public int typeId() {
        return 1;
    }
}

/**
 * 雙11活動(dòng)
 */
@Service
public class DoubleElevenGiftInfoStrategyService implements IGiftInfoStrategyService {

    @Override
    public GiftInfo getGiftInfo(int activityId) {
        // 雙11調(diào)用統(tǒng)一平臺(tái)接口獲取禮品信息
        GiftInfo giftInfo = new GiftInfo();
        giftInfo.setGiftId(902);
        giftInfo.setGiftName("空氣凈化器");
        return giftInfo;
    }

    @Override
    public int typeId() {
        return 2;
    }
}

package com.shawntime.designpattern.strategy.example;

import java.util.HashMap;
import java.util.Map;

import org.junit.Assert;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

/**
 * 禮品信息環(huán)境角色類
 */
@Component
public class GiftInfoContext implements ApplicationListener<ContextRefreshedEvent> {

    /**
     * 注入的策略
     */
    private Map<Integer, IGiftInfoStrategyService> giftInfoStrategyServiceMap = new HashMap<>();

    /**
     * 對(duì)外暴露的統(tǒng)一獲取禮品信息的返回
     */
    public GiftInfo getGiftInfo(int typeId, int activityId) {
        IGiftInfoStrategyService giftInfoStrategyService = giftInfoStrategyServiceMap.get(typeId);
        Assert.assertNotNull(giftInfoStrategyService);
        return giftInfoStrategyService.getGiftInfo(activityId);
    }

    public Map<Integer, IGiftInfoStrategyService> getGiftInfoStrategyServiceMap() {
        return giftInfoStrategyServiceMap;
    }

    public void setGiftInfoStrategyServiceMap(Map<Integer, IGiftInfoStrategyService> giftInfoStrategyServiceMap) {
        this.giftInfoStrategyServiceMap = giftInfoStrategyServiceMap;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
        if (applicationContext.getParent() == null) {
            Map<String, IGiftInfoStrategyService> infoStrategyServiceMap =
                    applicationContext.getBeansOfType(IGiftInfoStrategyService.class);
            infoStrategyServiceMap.values()
                    .forEach(strategyService -> {
                        int typeId = strategyService.typeId();
                        giftInfoStrategyServiceMap.put(typeId, strategyService);
                    });

        }
    }
}


/**
 * 禮品信息配置類
 */
@ComponentScan("com.shawntime.designpattern.strategy.example")
@Configuration
public class GiftInfoConfig {

}

/**
 * 禮品信息調(diào)用
 */
public class GiftInfoTest {

    private AnnotationConfigWebApplicationContext context;

    @Before
    public void before() {
        context = new AnnotationConfigWebApplicationContext();
        context.register(GiftInfoConfig.class);
        context.refresh();
    }

    @Test
    public void getGiftInfo() {
        GiftInfoContext giftInfoContext = context.getBean(GiftInfoContext.class);
        GiftInfo giftInfo = giftInfoContext.getGiftInfo(1, 2);
        Assert.assertNotNull(giftInfo);
    }
}
方案2:通過靜態(tài)方法配置
public interface IGiftInfoStrategyService {

    GiftInfo getGiftInfo(int activityId);
}

/**
 * 雙11活動(dòng)
 */
@Service
public class DoubleElevenGiftInfoStrategyService implements IGiftInfoStrategyService {

    // 靜態(tài)代碼塊中注冊(cè)關(guān)聯(lián)
    static {
        GiftInfoContext.registerProvider(2, DoubleElevenGiftInfoStrategyService.class);
    }

    @Override
    public GiftInfo getGiftInfo(int activityId) {
        // 雙11調(diào)用統(tǒng)一平臺(tái)接口獲取禮品信息
        GiftInfo giftInfo = new GiftInfo();
        giftInfo.setGiftId(902);
        giftInfo.setGiftName("空氣凈化器");
        return giftInfo;
    }
}

/**
 * 夏季購車節(jié)
 */
@Service
public class SummerBuyDayGiftInfoStrategyService implements IGiftInfoStrategyService {

    // 靜態(tài)代碼塊中注冊(cè)關(guān)聯(lián)
    static {
        GiftInfoContext.registerProvider(1, SummerBuyDayGiftInfoStrategyService.class);
    }

    @Resource
    private GiftInfoMapper giftInfoMapper;
    
    public GiftInfo getGiftInfo(int activityId) {
        // 從數(shù)據(jù)庫中查詢
        GiftInfo giftInfo = new GiftInfo();
        giftInfo.setGiftId(1);
        giftInfo.setGiftName("鐵鍋三件套");
        giftInfoMapper.getGiftInfoByActivityId(activityId)
        return giftInfo;
    }
}

/**
 * 禮品信息環(huán)境角色類
 */
@Component
public class GiftInfoContext {

    private static final Logger logger = LoggerFactory.getLogger(GiftInfoContext.class);

    // 策略映射map
    private static final Map<Integer, Class<?>> providers = new HashMap<>();

    // 提供給策略具體實(shí)現(xiàn)類的注冊(cè)返回
    public static void registerProvider(int subjectId, Class<?> provider) {
        providers.put(subjectId, provider);
    }

    // 對(duì)外暴露的獲取禮品信息接口返回
    public static GiftInfo getGiftInfo(int subjectId, int activityId) {
        Class<?> providerClazz = providers.get(subjectId);
        Assert.assertNotNull(providerClazz);
        Object bean = SpringUtils.getBean(providerClazz);
        Assert.assertNotNull(bean);
        if (bean instanceof IGiftInfoStrategyService) {
            IGiftInfoStrategyService strategyService = (IGiftInfoStrategyService) bean;
            return strategyService.getGiftInfo(activityId);
        }
        logger.error("Not Class with IGiftInfoListService: {}", providerClazz.getName());
        return null;
    }
}

public class GiftInfoTest {

    public GiftInfo getGiftInfo(int subjectId, int activityId) {
        GiftInfo giftInfo = GiftInfoContext.getGiftInfo(subjectId, activityId);
        Assert.assertNotNull(giftInfo);
        return giftInfo;
    }
}
方案3:通過spring自動(dòng)注入list、map

對(duì)于@Resource聲明的數(shù)組、集合類型,spring并不是根據(jù)beanName去找容器中對(duì)應(yīng)的bean,而是把容器中所有類型與集合(數(shù)組)中元素類型相同的bean構(gòu)造出一個(gè)對(duì)應(yīng)集合,注入到目標(biāo)bean中

public interface IGiftInfoStrategyService {

    GiftInfo getGiftInfo(int activityId);
     getTypeId();
}

/**
 * 夏季購車節(jié)
 */
@Service
public class SummerBuyDayGiftInfoStrategyService implements IGiftInfoStrategyService {

    @Resource
    private GiftInfoMapper giftInfoMapper;
    
    public GiftInfo getGiftInfo(int activityId) {
        // 從數(shù)據(jù)庫中查詢
        GiftInfo giftInfo = new GiftInfo();
        giftInfo.setGiftId(1);
        giftInfo.setGiftName("鐵鍋三件套");
        giftInfoMapper.getGiftInfoByActivityId(activityId)
        return giftInfo;
    }

     public int getTypeId() {
            return 1;
     }
}

/**
 * 雙11活動(dòng)
 */
@Service
public class DoubleElevenGiftInfoStrategyService implements IGiftInfoStrategyService {

    @Override
    public GiftInfo getGiftInfo(int activityId) {
        // 雙11調(diào)用統(tǒng)一平臺(tái)接口獲取禮品信息
        GiftInfo giftInfo = new GiftInfo();
        giftInfo.setGiftId(902);
        giftInfo.setGiftName("空氣凈化器");
        return giftInfo;
    }

    public int getTypeId() {
            return 2;
     }
}

/**
 * 禮品信息環(huán)境角色類
 */
@Component
public class GiftInfoContext {

    // Spring自動(dòng)注入
    @Resource
    private List<IGiftInfoStrategyService> giftInfoStrategyServiceList;

    // 對(duì)外暴露的統(tǒng)一獲取禮品信息的返回
    public GiftInfo getGiftInfo(int subjectId, int activityId) {
          Optional<IGiftInfoStrategyService> optional = giftInfoStrategyServiceList.stream()
                                                  .filter(service -> service.getTypeId = subjectId)
                                                  .findFrist();
        if (!optional.isPresent()) {
                Assert.assertNotNull(giftInfoStrategyService);
        }
  
        return optional.get().getGiftInfo(activityId);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容