让代码变美的第二天 - 策略模式

丑陋的模样

    public Fruit buyFruit(String name) {
        if ("苹果".equals(name)) {
            return new BuyApple().buy();
        } else if ("香蕉".equals(name)) {
            return new BuyBanana().buy();
        } else if ("西瓜".equals(name)) {
            // 买西瓜
            if (true) {
                // todo
            } else {
                // todo
            }
        }
        return null;
    }
  • 分支判断越来越多,方法就会越来越大,就算每个分支压缩到一个function,当超过一定数量也会很难看。最重要的是破坏了设计的开闭原则。

变美步骤

第一步 - 基本预期

思考:这个功能,这个方法改动到底是不是很频繁,新增的判断逻辑(if else)将来会不会很频繁。有个预期就行,如果没有预期,那就看实际改动次数。

  • 如果不频繁,建议就这样吧,只要结构清晰,方便review代码就行。不鼓励过度设计,毕竟开发时间都是有限的。
  • 如果很频繁,就看第二步

第二步 - 梳理核心逻辑

判断当前功能是不是都是由一个策略值,来决定后面整体流程,并且每个流程都不太相同,这样容易想到可以使用策略模式来进行优化。
如果当前功能不光有不同策略处理流程,还有共同的处理流程,那么可以把不同策略处理流程抽取出来,使用策略模式进行优化,共同的部分不在本文讨论范围内。

第三步 - 重构

只讨论使用spring项目
给策略进行定义,比如水果场景

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitScene {
    String value();
}

给所有策略对应的处理流抽象成一个方法,取个名字,比如买水果

public interface BuyFruit {
    Fruit buy();
}

定义每个策略对应处理流程,比如买苹果、买香蕉

@Component
@FruitScene("苹果")
public class BuyApple implements BuyFruit {
    @Override
    public Fruit buy() {
        System.out.println("买苹果");
        return new Fruit("苹果");
    }
}
@Component
@FruitScene("香蕉")
public class BuyBanana implements BuyFruit {
    @Override
    public Fruit buy() {
        System.out.println("买香蕉");
        return new Fruit("香蕉");
    }
}
  • 将来新增处理流程只需要新增一个类、方法

把定义的策略场景和处理流程进行关联

@Component
public class BuyFruitFactory {
    private static Map<String, BuyFruit> getBuyFruitMap = new HashMap<>();

    @Autowired
    private void setBuyFruitMap(List<BuyFruit> buyFruitList) {
        buyFruitList.forEach(fs -> {
            FruitScene fruitScene = fs.getClass().getAnnotation(FruitScene.class);
            if (fruitScene != null) {
                getBuyFruitMap.put(fruitScene.value(), fs);
            }
        });
    }

    public static Fruit buy(String fruitName) {
        return getBuyFruitMap.get(fruitName).buy();
    }
}

最终使用方式 - 优雅的一行代码

    public Fruit buyFruit2(String name) {
        return BuyFruitFactory.buy(name);
    }

点题

看起来整体代码变得更复杂了?哪里体现了开放封闭?
上面的例子只有两种策略,所以看起来代码变多了。如果策略很多,实际上重构后的代码基本都是固定的(无需更改),每次有新的策略流程,只需要实现BuyFruit接口即可(步骤2),做到了对扩展是开放的,而对修改是封闭的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值