当前位置:硬件测评 > 为什么我不再推荐枚举策略模式?

为什么我不再推荐枚举策略模式?

  • 发布:2023-10-09 07:20

1。为什么要讲策略模型

策略模式应该是比较常用的设计模式。调用者选择使用哪种策略来完成对数据的操作,即“一个类或其算法的行为可以在运行时改变”

我个人的理解就是把一些除了流程之外都一样的功能封装成策略,然后调用者可以选择自己想要数据执行什么流程策略。常见的例子就是根据用户分类推荐不同的排名(不同的用户关注点导致不同的推荐排名)

和单例模式一样,随着时间的发展,我不再推荐经典的策略模式。我建议简单策略使用枚举策略模式,复杂策略使用工厂策略模式。下面介绍一个例子。我们的要求是:对于一个股票数据列表,给出低价列表、高价列表、涨幅列表。只是排序条件不同,更适合作为策略模式的例子

2。经典策略模式

数据DTO

@Data 
公共 库存 {

//股票交易代码
private 字符串代码;
私人 双倍价格;

私人 双上升;
}

抽象策略接口

公共 接口 策略 { 

/**
* @param 源源数据

*/

列表 排序(列表来源)
}

实施我们的策略课程

/**  
 * 高价榜  
 */
  
公共 班级  HighPriceRank 实现 策略 {  
  
    @Override       公共 列表 排序(列表来源) {  
        return www.sychzs.cn()  
                .sorted(Comparator.comparing(Stock::getPrice).reversed())  
                .collect(收藏家.toList());
    }  
}  
  
/**  
 * 低价榜  
*/   
公共  LowPriceRank  实施 策略 {  
  
    @Override  
    公共 列表 排序(列表 来源) {  
        返回 www.sychzs.cn()  
                .sorted(Comparator.comparing(Stock::getPrice) )  
                .collect(Collectors.toList());
    }  
}  
  
/**  
 * 高升榜  
*/   
酒吧lic class HighRiseRank 实现  策略 
{  
  
    @Override
    公共 列表 排序(列表来源)  {  
        return www.sychzs.cn()
                .sorted(Comparator.comparing(Stock::getRise).reversed())  
                .collect(Collectors.toList());
    }  
}  

经典的上下文类,

公共  上下文 {  
    私人 策略 策略;
      
    public void setStrategy (策略策略) {  
        这个.策略= 策略;
    }  
  
    公共 列表 getRank (列表来源) {  
        返回 strategy.sort(source);
    }  
}  

于是我们顺礼成章地得到调用类–排行榜实例RankServiceImpl

@Service 
公共 RankServiceImpl {

/**
* 数据服务.getSource() 提供原始库存数据
private DataService dataService;

/**
* 前端 传入列表类型,返回排序后的列表 * @param
等级类型列表类型
* @return 列表数据
*/

列表 getRank(字符串排名类型) {
// 创建上下文
       Context context  = new Context(); //在此选择策略
switch (rankType) {
case “高价”
context.setStrategy(new HighPriceRank()); ;
案例 “低价”:                                   context.setStrategy(new LowPr冰排名());
断裂“HighRise”
HighRiseRank());
断裂
默认 :
》rankType 未找到");
                                              return context.getRank(dataService.getSource());
}
}

我们可以看到经典的方法,它创建了一个接口和三个策略类,这是相当冗长的。调用类的实现也存在问题。添加新的策略类需要修改列表实例(这个可以用抽象工厂来解决,但是复杂度又增加了)。另外,我们还有更好的选择,所以这里不再推荐经典策略模式

3。基于枚举的策略模式

对于这个简单的策略,建议使用枚举进行优化。枚举的本质是创建静态类的集合。

下面我直接举个例子,让大家直观感受一下

枚举策略课

public enum RankEnum { 
//以下三个是策略示例
HighPrice {
@覆盖
公共列表排序(列表来源) {
                                                                                                                 。排序(Comparator.comparing(Stock :: getPrice).reversed())
             。 },
LowPrice {
@ 覆盖
源) {
.stream()
.sorted(Comparator.comparing(Stock) ::getPrice))
.collect(Collectors.toList()); }
},
高层{
@Override
公共列表排序(列表来源) {
来源.stream()
.sorted(Comparator.comparing(Stock::getRise).reversed())
.collect(Collectors.toList());
                                                                          //这里定义策略接口
公共 抽象列表排序(列表) 来源);
}

对应的调用类也进行了优化,列表实例RankServiceImpl

@Service 
公共 RankServiceImpl {

/**
* 数据服务.getSource() 提供原始库存数据
private DataService dataService;

/**
* 前端传入列表类型,返回排序后的列表
*
列表类型看起来像RankEnum .www.sychzs.cn()
*
列表getRank(字符串rankType)
{
//获取策略,如果这里没有匹配到,会抛出IllegalArgumentException throw
                       
//然后执行策略
​​return排名.排序(dataService.getSource());
}
}

可以看出,如果策略简单的话,基于枚举的策略模式优雅得多,调用者也实现了0修改。然而,正确使用枚举策略模式需要额外考虑以下几点。

  • 枚举的策略类是公共的、静态的,也就是说这个策略流程中不能引入非静态的部分,扩展性受到限制

  • 策略模型的目标之一是出色的可扩展性和可维护性。最好添加或修改某个策略类而不改变其他类。如果枚举策略太多或者流程复杂,维护就会困难,可维护性有限

4。基于工厂的战略模式

为了解决良好的扩展性和可维护性的问题,我推荐下面利用spring自带的beanFactory的优势来实现基于工厂的策略模式。

策略类变更只是添加@Service注解,并指定Service

的value属性
/** 
* 高价表
* 请注意Service.value = HighPrice,这是我们的key,下同
*/
@Service("高价")
公共 HighPriceRank 实施 策略 {

@Override
公共列表排序(列表来源) {
return www.sychzs.cn()
          .collect(Collectors.toList());                                                       )
(“低价”)
公共 LowPriceRank 实现策略 {

@Override
公共列表排序(列表源) {
return www.sychzs.cn()
      .sorted(Comparator.comparing(股票::getPrice))  
                .collect(Collectors.toList());
    }  
}  
  
/**  
 * 高升榜  
*/   
@服务("高层" )  
公共 HighRiseRank 实现  策略 {  
  
    @覆盖  
    public 列表 排序(列表)  来源) {  
        返回 来源.stream()  
                .sorted(Comparator.comparing(Stock::getRise).reversed())  
                 .collect(Collectors.toList());
    }  
}  

类调用修改,新增接入借助spring工厂特性,完成策略类

@Service 
公共 RankServiceImpl {

/**
* 数据服务.getSource() 提供原始库存数据
private DataService dataService;
/**
* 使用注释 @Resource@Autowired 直接获取所有策略类
* key = 的值@服务
* /

@资源
​​私人
地图rankMap;

/**
* 前端传入List类型,返回排序后的列表
*
* @return
列出单个数据
* /
getRank(StringrankType) {
//确定该策略是否存在
if (!rankMap. containsKey(rankType)) {
抛出 new IllegalArgumentException("未找到rankType" );
}
//获取策略实例
策略rank =rankMap.get(rankType);
//执行策略
returnrank.sort(dataService.getSource());
}
}

如果读者没有使用Spring,也可以找到对应的实现框架的工厂模式,或者自己实现一个抽象工厂。

工厂策略模式比枚举策略模式更加冗长,但也更加灵活,易于扩展,易于维护。因此,对于简单的策略推荐使用枚举策略模式,对于复杂的策略推荐使用工厂策略模式。

相关文章

最新资讯

热门推荐