一、策略模式的使用

1、策略模式定义:

策略模式(Strategy Pattern)定义了一组策略,分别在不同类中封装起来,每种策略都可以根据当前场景相互替换,从而使策略的变化可以独立于操作者。比如我们要去某个地方,会根据距离的不同来选择不同的出行方式,这些出行方式即不同的策略。

个人理解:
就是定义了一个策略接口,然后有多种策略实现类去实现策略接口。

2、何时使用策略模式

阿里开发规约-编程规约-控制语句-第六条 :超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。

相信大家都见过这种代码:


if (conditionA) {
    逻辑1
} else if (conditionB) {
    逻辑2
} else if (conditionC) {
    逻辑3
} else {
    逻辑4
}

这种代码虽然写起来简单,但是很明显违反了面向对象的2个基本原则:

  • 单一职责原则(一个类应该只有一个发生变化的原因):因为之后修改任何一个逻辑,当前类都会被修改
  • 开闭原则(对扩展开发,对修改关闭):如果此时需要添加(删除)某个逻辑操作,那么就会修改原来的代码

尤其是当if-else 块中的代码量比较大时,后续代码的扩展和维护就会逐渐变得非常困难且容易出错,使用switch 语句也同样避免不了以上两个问题。

比较好的实践:

  • if-else 不超过 2 层,块中代码 1~5 行,直接写到块中,否则封装为方法
  • if-else 超过 2 层,但块中的代码不超过 3 行,尽量使用卫语句
  • if-else 超过 2 层,且块中代码超过 3 行,尽量使用策略模式

3、策略模式实践

在Spring中,如何巧妙的运用策略模式。

3.1、需求背景

我们按照前面说的,我们以去某个地方为由,会根据距离的不同而选择不同的出行方式。

出行的策略(方式):

  • 步行
  • 出租车
  • 地铁

3.2、第一步,定义策略接口

首先定义策略接口,包括两个方法:

  1. 获取策略类型的方法
  2. 处理策略逻辑的方法
public interface ActionHandler {
	/**
	*	获取策略的类型
	*/
    public String actionMethod();
	
	/**
	*	处理策略的逻辑
	*/
    public Object handler();
}

3.3、第二步,相关策略实现

这里我定义了一个枚举类,用来表示策略的类型及其含义:

public enum ActionMethodEnum {
    WALK("by_walk","步行"),
    CAR("by_car","出租车"),
    SUBWAY("by_subway","地铁"),
    CYCLE("by_cycle","自行车");

    private String method;
    private String desc;


    ActionMethodEnum(String method,String desc){
        this.method = method;
        this.desc = desc;
    }


    public String getMethod() {
        return method;
    }

    public String getDesc() {
        return desc;
    }
}

步行策略实现类:

@Component
public class ByWalkActionHandler implements ActionHandler {
    @Override
    public String actionMethod() {
        return ActionMethodEnum.WALK.getMethod();
    }

    @Override
    public Object handler() {
        System.out.println("步行出行。。");
        return ActionMethodEnum.WALK.getDesc();
    }
}

出租车策略实现类:

@Component
public class ByCarActionHandler implements ActionHandler {

    @Override
    public String actionMethod() {
        return ActionMethodEnum.CAR.getMethod();
    }

    @Override
    public Object handler() {
        System.out.println("出租车出行。。。");
        return ActionMethodEnum.CAR.getDesc();
    }
}

地铁策略实现类:

@Component
public class BySubwayActionHandler implements ActionHandler {
    @Override
    public String actionMethod() {
        return ActionMethodEnum.SUBWAY.getMethod();
    }

    @Override
    public Object handler() {
        System.out.println("地铁出行。。。");
        return ActionMethodEnum.SUBWAY.getDesc();
    }
}

3.4、建立策略的简单工厂

Tips:
这里使用简单工厂是为了管理我们的策略实现类,将这些策略放入一个Map集合中,后续可以根据策略的类型获取对应的策略处理器。

@Component
public class ActionMethodContext implements InitializingBean, ApplicationContextAware {

    private ApplicationContext applicationContext;

    private Map<String, ActionHandler> methodMap = new HashMap<>();

	/**
	 * 将Spring容器中所有实现了策略接口的类添加到Map集合中 
	*/
    @Override
    public void afterPropertiesSet() throws Exception {
        applicationContext.getBeansOfType(ActionHandler.class).values()
                .stream().forEach(actionHandler -> methodMap.put(actionHandler.actionMethod(),actionHandler));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 根据出行类型获取对应的策略方法
     * @param actionMethod
     * @return
     */
    public ActionHandler getActionMethod(String actionMethod){

        return methodMap.getOrDefault(actionMethod,new ByWalkActionHandler());
    }
}

4、使用 & 测试

创建了一个controller来简单的测试:

@RestController
public class ActionController {

    @Autowired
    ActionMethodContext actionMethodContext;

    @GetMapping("/action")
    public String doAction(String actionMethod){
        ActionHandler actionHandler = actionMethodContext.getActionMethod(actionMethod);
        String result = (String) actionHandler.handler();
        return result;
    }

}

使用postman简单的测试一下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Factory 只负责获取 Handler,Handler 只负责处理具体的提交,Service 只负责逻辑编排,从而达到功能上的 “低耦合高内聚”。

5、扩展

如果我们需要加入一个新的策略,比如自行车出行,我们只需要添加一个新的策略实现即可:

@Component
public class ByCycleActionHandler implements ActionHandler {
    @Override
    public String actionMethod() {
        return ActionMethodEnum.CYCLE.getMethod();
    }

    @Override
    public Object handler() {
        System.out.println("自行车出行。。。");
        return ActionMethodEnum.CYCLE.getDesc();
    }
}

此时不需要修改原有的逻辑,在Spring容器重启时会自动将自行车策略类添加到我们的简单工厂类中。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GoF 的 23 种设计模式的分类,现在对各个模式的功能进行介绍。 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。 原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。 工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。 抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。 建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。 代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。 适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。 桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。 装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。 外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。 享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。 组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。 模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。 策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。 命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。 职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。 状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。 观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。 中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。 迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。 访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。 备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。 解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。
策略模式是一种行为设计模式,它允许在运行时选择算法的行为。在Java中,可以通过创建一个接口来定义算法族,然后创建具体的类来实现这些算法。然后,可以创建一个上下文类,该类将使用这些算法中的一个来完成其任务。在运行时,可以选择不同的算法来使用。 以下是一个使用Java实现策略模式的示例代码: // 定义算法接口 interface Strategy { int doOperation(int num1, int num2); } // 实现算法类 class OperationAdd implements Strategy { public int doOperation(int num1, int num2) { return num1 + num2; } } class OperationSubtract implements Strategy { public int doOperation(int num1, int num2) { return num1 - num2; } } class OperationMultiply implements Strategy { public int doOperation(int num1, int num2) { return num1 * num2; } } // 创建上下文类 class Context { private Strategy strategy; public Context(Strategy strategy){ this.strategy = strategy; } public int executeStrategy(int num1, int num2){ return strategy.doOperation(num1, num2); } } // 使用策略模式 public class StrategyPatternDemo { public static void main(String[] args) { Context context = new Context(new OperationAdd()); System.out.println("10 + 5 = " + context.executeStrategy(10, 5)); context = new Context(new OperationSubtract()); System.out.println("10 - 5 = " + context.executeStrategy(10, 5)); context = new Context(new OperationMultiply()); System.out.println("10 * 5 = " + context.executeStrategy(10, 5)); } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值