文章目录

  • 描述
    • 定义
    • 类型
    • 动机
    • UML类图
    • 时序图
  • 实现
    • 主要角色
    • 示例
  • 适用场景
  • 优点
  • 缺点
  • 相关模式

描述

定义

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。称为政策模式(Policy)。

类型

对象行为型模式

动机

在有多种算法相似的情况下,使用if…else所带来的复杂和难以维护。将这些算法封装成一个一个的类,使得客户端可以根据外部条件任意选择不同策略来解决不同问题。

UML类图

时序图

实现

主要角色

  • Strategy:策略接口
    • 定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。
  • ConcreteStrategy:具体策略
    • 实现Strategy接口的某具体算法。
  • Context:上下文
    • 用一个ConcreteStrategy对象来配置。
    • 维护一个对Strategy对象的引用。
    • 可定义一个接口来让Strategy访问它的数据。

示例

  • Strategy:策略接口。当算法被调用时,Context可以将该算法所需要的所有数据都传递给该Strategy。或者,Context可以将自身作为一个参数传递给Strategy操作。这就让Strategy在需要时可以回调Context获取数据。

      interface Strategy {
         void algorithm(Context context);
      }
    
  • ConcreteStrategy:具体策略

      public class ConcreteStrategyA implements Strategy {
         @Override
         void algorithm(Context context) {
            System.out.println("策略 A");
         }
      }
    
      public class ConcreteStrategyB implements Strategy {
         @Override
         void algorithm(Context context) {
            System.out.println("策略 B");
         }
      }
    
  • Context:上下文

      public class Context {
         private Strategy strategy;
    
         public void setStrategy(Strategy strategy) {
            this.strategy = strategy;
         }
       
         public void algorithm() {
            strategy.algorithm(this);
         }
      }
    
  • Client:客户类。客户通常创建并传递一个ConcreteStrategy对象给该Context;这样,客户仅与Context交互。在策略模式中,应当由客户端自己决定在什么情况下使用什么具体策略。

      public class Client {
          public static void main(String[] args) {
              Context context = new Context();
    
      		context.setStrategy(new ConcreteStrategyA());
      		context.algorithm();
      		
      		context.setStrategy(new ConcreteStrategyB());
      		context.algorithm();
          }
      }
    

适用场景

  • 如果系统中有许多类之间的区别仅在于它们的行为,而系统需要动态地在其中选择一种。
  • 一个类中以多个条件语句的形式定义了多种行为。
  • 不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。

优点

  • 可重用的算法系列。Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。
  • 一个替代继承的方法,易于切换、易于扩展。将算法封装在独立的Strategy类中使得你可以独立于其Context改变它。
  • 消除了多重条件判断。将行为封装在一个个独立的Strategy类中消除了这些条件语句。
  • 符合开闭原则。用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。

缺点

  • 客户必须了解不同的Strategy。客户要选择一个合适的Strategy就必须知道这些Strategy到底有何不同。此时可能不得不向客户暴露具体的实现问题。
  • Strategy和Context之间的通信开销。无论各个ConcreteStrategy实现的算法是简单还是复杂,它们都共享Strategy定义的接口。因此很可能某些ConcreteStrategy不会都用到所有通过这个接口传递给它们的信息;简单的ConcreteStrategy可能不使用其中的任何信息。
  • 增加了类的数目。可以通过使用享元模式在一定程度上减少对象的数量。

相关模式

  • Flyweight:Strategy对象经常是很好的轻量级对象。