策略模式

概述

要完成一项任务,可以有多种不同的方式,外出旅游时可以选择多种不同的出行方式,如自行车、坐汽车、坐高铁或乘飞机等,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成任务

在软件开发中,一项功能也有很多算法可以实现,如果我们直接把多种算法集中在一个类,或者说使用条件判断语句来进行选择,则会增加代码复杂性,不利于维护

为了解决这些问题,可以定义一些独立的类来封装不同的算法,每一类封装一个具体的算法,将每一个封装算法的类称之为策略(Strategy)。为了保证策略的一致性,一般会用一个抽象的策略类来做算法的定义,每种具体算法对应于一个具体策略类


模式分析

说到策略模式就不得不提一下状态模式了,一个是对状态的封装,另一个则是对算法的封装,因此实现方式上两者有许多共同点。策略模式是对算法的封装,把对象和算法分割开来

由此可以得出结构类图如下:

环境类(Context)是需要使用算法的对象,它在解决某个问题时可以采用多种策略,在环境类中维护一个对抽象策略类的引用实例,用于定义所采用的策略。假如我们不使用策略模式,可能会存在如下代码:

public class Context {
    ...
    public void algorithm(String type) {
		...
         if(type == "strategyA") {
             // 算法A
         } else if(type == "strategyB") {
             // 算法B
         } else if(type == "strategyC") {
             // 算法C
         }
        ...
    }
    ...
}

客户端要调用 Context 类的 algorithm() 方法时,需要根据所传入的参数来选择具体算法,这将导致代码不利于维护,如果需要修改或增加算法,则要修改代码

通过引入一个抽象策略类(Strategy),在其中定义抽象算法,每一个继承它的具体策略类(ConcreteStrategy)使用具体算法实现某个业务逻辑。出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可

public abstract class AbstractStrategy {
	public abstract void algorithm();
}

将每一种具体算法作为该抽象策略类的子类

public class ConcreteStrategyA extends AbstractStrategy {
	public void algorithm() {
        // 算法A
    }
}

对于环境类,在它与抽象策略类之间建立一个关联关系

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

对于用户而言,使用环境类时只需注入一个具体策略对象即可。用户可以灵活更换具体策略类,比如使用配置文件,增加新的具体策略类也很方便,因此策略模式相当于“即插即用的算法”

需要注意的是,策略模式并不负责“哪一个具体策略类适用于哪一种情况”这个决定,换言之,应当由客户决定在什么情况下使用什么具体策略角色。如果环境对象存在多种状态,而且这些状态之间可以进行转换,则应使用状态模式。如果环境对象只有一个状态,那么应当使用策略模式

posted @ 2020-06-12 08:59  低吟不作语  阅读(550)  评论(0编辑  收藏  举报