日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

為什么我不再推薦枚舉策略模式?

 

一、為什么講策略模式

策略模式,應(yīng)該是工作中比較常用的設(shè)計(jì)模式,調(diào)用方自己選擇用哪一種策略完成對(duì)數(shù)據(jù)的操作,也就是“一個(gè)類的行為或其算法可以在運(yùn)行時(shí)更改”

我個(gè)人的理解是 將一些除了過程不同其他都一樣的函數(shù)封裝成策略,然后調(diào)用方自己去選擇想讓數(shù)據(jù)執(zhí)行什么過程策略。常見的例子為根據(jù)用戶分類推薦不同的排行榜(用戶關(guān)注點(diǎn)不一樣,推薦榜單就不一樣)

和單例模式一樣,隨著時(shí)間發(fā)展,我不再推薦經(jīng)典策略模式,更推薦簡單策略用枚舉策略模式,復(fù)雜地用工廠策略模式。下面引入一個(gè)例子,我們的需求是:對(duì)一份股票數(shù)據(jù)列表,給出低價(jià)榜、高價(jià)榜、漲幅榜。這其中只有排序條件的區(qū)別,比較適合作為策略模式的例子

二、經(jīng)典策略模式

數(shù)據(jù)DTO

@Data
public class Stock {

    // 股票交易代碼
    private String code;

    // 現(xiàn)價(jià)
    private Double price;

    // 漲幅
    private Double rise;
}

抽象得到的策略接口

public interface Strategy {

    /**
     * 將股票列表排序
     *
     * @param source 源數(shù)據(jù)
     * @return 排序后的榜單
     */
    List<Stock> sort(List<Stock> source);
}

實(shí)現(xiàn)我們的策略類

/**
 * 高價(jià)榜
 */
public class HighPriceRank implements Strategy {

    @Override
    public List<Stock> sort(List<Stock> source) {
        return source.stream()
                .sorted(Comparator.comparing(Stock::getPrice).reversed())
                .collect(Collectors.toList());
    }
}

/**
 * 低價(jià)榜
 */
public class LowPriceRank implements Strategy {

    @Override
    public List<Stock> sort(List<Stock> source) {
        return source.stream()
                .sorted(Comparator.comparing(Stock::getPrice))
                .collect(Collectors.toList());
    }
}

/**
 * 高漲幅榜
 */
public class HighRiseRank implements Strategy {

    @Override
    public List<Stock> sort(List<Stock> source) {
        return source.stream()
                .sorted(Comparator.comparing(Stock::getRise).reversed())
                .collect(Collectors.toList());
    }
}

經(jīng)典的Context類,

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

    public List<Stock> getRank(List<Stock> source) {
        return strategy.sort(source);
    }
}

于是 我們順禮成章地得到調(diào)用類--榜單實(shí)例RankServiceImpl

@Service
public class RankServiceImpl {

    /**
     * dataService.getSource() 提供原始的股票數(shù)據(jù)
     */
    @Resource
    private DataService dataService;

    /**
     * 前端傳入榜單類型, 返回排序完的榜單
     *
     * @param rankType 榜單類型
     * @return 榜單數(shù)據(jù)
     */
    public List<Stock> getRank(String rankType) {
        // 創(chuàng)建上下文
        Context context = new Context();
        // 這里選擇策略
        switch (rankType) {
            case "HighPrice":
                context.setStrategy(new HighPriceRank());
                break;
            case "LowPrice":
                context.setStrategy(new LowPriceRank());
                break;
            case "HighRise":
                context.setStrategy(new HighRiseRank());
                break;
            default:
                throw new IllegalArgumentException("rankType not found");
        }
        // 然后執(zhí)行策略
        return context.getRank(dataService.getSource());
    }
}

我們可以看到經(jīng)典方法,創(chuàng)建了一個(gè)接口、三個(gè)策略類,還是比較啰嗦的。調(diào)用類的實(shí)現(xiàn)也待商榷,新增一個(gè)策略類還要修改榜單實(shí)例(可以用抽象工廠解決,但是復(fù)雜度又上升了)。加之我們有更好的選擇,所以此處不再推薦經(jīng)典策略模式

三、基于枚舉的策略模式

這里對(duì)這種簡單的策略,推薦用枚舉進(jìn)行優(yōu)化。枚舉的本質(zhì)是創(chuàng)建了一些靜態(tài)類的集合。

我下面直接給出例子,大家可以直觀感受一下

枚舉策略類

public enum RankEnum {
    // 以下三個(gè)為策略實(shí)例
    HighPrice {
        @Override
        public List<Stock> sort(List<Stock> source) {
            return source.stream()
                    .sorted(Comparator.comparing(Stock::getPrice).reversed())
                    .collect(Collectors.toList());
        }
    },
    LowPrice {
        @Override
        public List<Stock> sort(List<Stock> source) {
            return source.stream()
                    .sorted(Comparator.comparing(Stock::getPrice))
                    .collect(Collectors.toList());
        }
    },
    HighRise {
        @Override
        public List<Stock> sort(List<Stock> source) {
            return source.stream()
                    .sorted(Comparator.comparing(Stock::getRise).reversed())
                    .collect(Collectors.toList());
        }
    };

    // 這里定義了策略接口
    public abstract List<Stock> sort(List<Stock> source);
}

對(duì)應(yīng)的調(diào)用類也得以優(yōu)化,榜單實(shí)例RankServiceImpl

@Service
public class RankServiceImpl {

    /**
     * dataService.getSource() 提供原始的股票數(shù)據(jù)
     */
    @Resource
    private DataService dataService;

    /**
     * 前端傳入榜單類型, 返回排序完的榜單
     *
     * @param rankType 榜單類型 形似 RankEnum.HighPrice.name()
     * @return 榜單數(shù)據(jù)
     */
    public List<Stock> getRank(String rankType) {
        // 獲取策略,這里如果未匹配會(huì)拋 IllegalArgumentException異常
        RankEnum rank = RankEnum.valueOf(rankType);
        // 然后執(zhí)行策略
        return rank.sort(dataService.getSource());
    }
}

可以看到,如果策略簡單的話,基于枚舉的策略模式優(yōu)雅許多,調(diào)用方也做到了0修改,但正確地使用枚舉策略模式需要額外考慮以下幾點(diǎn)。

  1. 枚舉的策略類是公用且靜態(tài),這意味著這個(gè)策略過程不能引入非靜態(tài)的部分,擴(kuò)展性受限
  2. 策略模式的目標(biāo)之一,是優(yōu)秀的擴(kuò)展性和可維護(hù)性,最好能新增或修改某一策略類時(shí),對(duì)其他類是無改動(dòng)的。而枚舉策略如果過多或者過程復(fù)雜,維護(hù)是比較困難的,可維護(hù)性受限

四、基于工廠的策略模式

為了解決良好的擴(kuò)展性和可維護(hù)性,我更推薦以下利用spring自帶beanFactory的優(yōu)勢,實(shí)現(xiàn)一個(gè)基于工廠的策略模式。

策略類改動(dòng)只是添加了@Service注解,并指定了Service的value屬性

/**
 * 高價(jià)榜
 * 注意申明 Service.value = HighPrice,他是我們的key,下同
 */
@Service("HighPrice")
public class HighPriceRank implements Strategy {

    @Override
    public List<Stock> sort(List<Stock> source) {
        return source.stream()
                .sorted(Comparator.comparing(Stock::getPrice).reversed())
                .collect(Collectors.toList());
    }
}

/**
 * 低價(jià)榜
 */
@Service("LowPrice")
public class LowPriceRank implements Strategy {

    @Override
    public List<Stock> sort(List<Stock> source) {
        return source.stream()
                .sorted(Comparator.comparing(Stock::getPrice))
                .collect(Collectors.toList());
    }
}

/**
 * 高漲幅榜
 */
@Service("HighRise")
public class HighRiseRank implements Strategy {

    @Override
    public List<Stock> sort(List<Stock> source) {
        return source.stream()
                .sorted(Comparator.comparing(Stock::getRise).reversed())
                .collect(Collectors.toList());
    }
}

調(diào)用類修改較大,接入借助spring工廠特性,完成策略類

@Service
public class RankServiceImpl {

    /**
     * dataService.getSource() 提供原始的股票數(shù)據(jù)
     */
    @Resource
    private DataService dataService;
    /**
     * 利用注解@Resource和@Autowired特性,直接獲取所有策略類
     * key = @Service的value
     */
    @Resource
    private Map<String, Strategy> rankMap;

    /**
     * 前端傳入榜單類型, 返回排序完的榜單
     *
     * @param rankType 榜單類型 和Service注解的value屬性一致
     * @return 榜單數(shù)據(jù)
     */
    public List<Stock> getRank(String rankType) {
        // 判斷策略是否存在
        if (!rankMap.containsKey(rankType)) {
            throw new IllegalArgumentException("rankType not found");
        }
        // 獲得策略實(shí)例
        Strategy rank = rankMap.get(rankType);
        // 執(zhí)行策略
        return rank.sort(dataService.getSource());
    }
}

若讀者使用的不是Spring,也可以找找對(duì)應(yīng)框架的工廠模式實(shí)現(xiàn),或者自己實(shí)現(xiàn)一個(gè)抽象工廠

工廠策略模式會(huì)比枚舉策略模式啰嗦,但也更加靈活、易擴(kuò)展性和易維護(hù)。故簡單策略推薦枚舉策略模式,復(fù)雜策略才推薦工廠策略模式

 

作者:ColdSmog

原文鏈接:
https://www.cnblogs.com/hyry/p/16068762.html

分享到:
標(biāo)簽:枚舉 策略
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績?cè)u(píng)定