结构
策略模式(政策模式)定义一系列的算法,通过实现接口将其一个个封装起来,使它们可以相互替换。
策略模式包含以下3种角色:
- 策略(Strategy):
是一个接口类,用来定义与问题相关的若干个抽象方法(也可以使用抽象类)。 - 上下文(Context):
依赖于策略接口类的类(面向策略设计的类)。即该类中包含策略声明的变量(上转型),同时该类提供方法委托策略变量调用具体策略类所实现的接口的方法。 - 具体策略(ConcreteStrategy):
实现策略接口的类,即实现策略接口中所定义的抽象方法,给出具体算法。
策略模式中的角色UML类图如下图:
优点
- 上下文(Context) 和具体策略(ConcreteStrategy) 类是松耦合关系,即上下文类只要知道它要使用某一个实现策略(Strategy) 接口类的实例,但并不需要知道具体是哪一个类(使用上转型,Strategy strategy = new ConcreteStrategy())。
- 满足 “开-闭”原则(让设计对扩展开放,对修改关闭)。 当增加新的 具体策略类 时,不需要修改 上下文类 的代码,上下文就可以引用新的 具体策略类 的实例。
注:关于开闭原则,将设计分为核心部分和需求部分,核心部分是整个设计的基本结构,不是用来应对需求变化的,因此不能因为用户的需求变化而变化,此部分对修改关闭。当有需求变更和追加时,只允许在需求部分进行追加,而不需要也不允许修改现有的模块,即对扩展开放。
适用场所
- 一个类定义了多种行为,且这些行为在这个类的方法中以多个条件语句的形式出现,那么使用策略模式可以避免在类中使用大量的条件语句。
- 主要类(即上下文类 )不希望暴露复杂的、与算法相关的数据结构,那么可以使用策略模式封装算法,即将算法分别封装到具体策略 中。
与继承机制的对比
众所周知,面向对象型语言的一大特性就是继承。
通过继承可以改进对象的行为,子类可以重写父类的方法来改变该方法的行为,使得子类的对象具有和父类对象不同的行为。
但是,如果按照继承机制的用法,将父类的某个方法的内容的不同变体交给对应的子类去实现,就会使得这些实现和父类中的其他代码是高耦合关系,即父类的任何改动都会影响到所有的子类。 考虑到系统扩展性和复用性,应当注意面向对象的一个基本原则:少用继承,多用组合。
策略模式采用组合结构,将上下文类 的某个方法的内容的不同变体分别封装在不同的具体策略 中,而该上下文类 仅仅依赖于这些具体策略</