策略模式(Strategy Pattern,对象行为型模式)

来源:互联网 发布:淘宝浏览器打开就关闭 编辑:程序博客网 时间:2024/05/21 22:26

意图

定义一系列算法,把这些算法一个个封装成拥有相同接口的单独类,并且使他们之间可以互换。
把算法整个换掉。
定义一系列算法,把这些算法一个个封装起来,并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。

适用性

在存在以下情况时使用Strategy模式
1. 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
2. 需要使用一个算法的不同变体
3. 算法使得客户不应该知道的数据。可以使用策略模式以避免暴漏复杂的、与算法相关的数据结构。
4. 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以替代这些条件语句。
5. 系统需要能够在几个算法中快速的切换
6. 系统中有一些类他们仅行为不同,可以使用策略模式进行重构
7. 系统中存在多重条件选择语句时,可以使用策略模式进行重构
8. 注意:策略模式中不可以同时使用多于一个的算法。

结构

这里写图片描述

参与者

Strategy

1.定义所有支持的算法的公共接口。Context使用这个接口来调用某个ConcreteStrategy定义的算法。

ConcreteStrategy

1.以Strategy接口实现具体算法。

Context

  1. 用一个ConcreteStrategy对来配置
  2. 维护一个对Strategy对象的引用
  3. 可以定义一个接口来让Strategy访问它的数据。

代码

public interface Strategy {    public void method1();    public void method2();}public class ConcreteStrategy implements Strategy{    public void method1() {        System.out.println("===ConcreteStrategy===method1====");    }    public void method2() {        System.out.println("===ConcreteStrategy===method2====");    }}public class Context {    private Strategy strategy;    public Context(Strategy strategy){        this.strategy = strategy;    }    public void execute(){        strategy.method1();        strategy.method2();    }}public class Client {    public static void main(String[] args) {        Context c = new Context(new ConcreteStrategy());        c.execute();    }}

协作

  1. Strategy和Context相互作用以实现选定的算法。当算法被调用时,Context可以将该算法所需要的所有数据都传递给Strategy。或者,Context可以将自身作为一个参数传递给Strategy操作。这就让Strategy在需要时可以回调Context。
  2. Context将它的客户的请求转发给它的Strategy。客户通常创建并传递一个ConcreteStrategy对给该Context;这样,客户仅与Context交互。通常有一系列的ConcreteStrategy类可供客户从中选择。

效果

相关算法系列

Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。

一个替代继承的方法

将算法封装在独立的Strategy类中使得你可以独立于其Context改变它,使它易于切换、理解和扩展。将算法的使用和算法本身分类,达到高内聚,低耦合。

消除一些条件语句

避免程序使用多重条件转移语句,使系统更灵活,并易于扩展 。

实现的选择

Strategy模式可以提供相同行为的不同实现。客户可以根据不同时间、空间权衡取舍要求从不同策略中进行选择。

客户必须了解不同的Strategy

一个客户要选择一个合适的Strategy就必须知道这些Strategy到底有何不同。此时可能不得不向客户暴露具体的实现问题。因此仅当这些不同行为变体与客户相关的行为时,才需要使用Strategy。

Strategy和Context之间的通信开销

无论各个ConcreteStrategy实现的算法是简单还是复杂,它们都共享Strategy定义的接口。因此很可能某些ConcreteStrategy不会都用到所有通过这个接口传递给它们的信息;简单的ConcreteStrategy可能不适用其中的任何信息!这意味着有时Context会创建和初始化一些永远不会用到的参数。如果存在这样的问题,那么将需要在Strategy和Context之间更尽兴机密的耦合。

增加了对象的数目

Strategy增加了一个应用中的对象的数目。有时你可以将Strategy实现为可提供各Context共享的无状态的对象来减少一个开销。任何其余的状态都由Context维护。Context在每一次对Strategy对象的请求中都将这个状态传递过去。共享的Strategy不应在各次调用之间维护状态。可以使用工厂方法来解决,还可以使用享元模式来完成对象的共享,减少系统开销。

实现

定义Strategy和Context接口

Strategy和Context接口必须使得ConcreteStrategy能够有效的访问它所需要的Context中的任何数据。反之亦然。一种办法是让Context将数据放到参数中传递给Strategy操作,也就是说,将数据发送给Strategy。这使得Strategy和Context解耦。但另一方面,Context可能发送一些Strategy不需要的参数。
另一种方法是让Context将自身作为一个参数传递给你Strategy,该Strategy再显示地向该Context请求数据。或者,Strategy可以存储对它的Context的一个引用,这样根本不在需要传递任何东西。这两种情况下,Strategy都可以请求到它所需要的数据。但现在Context必须对它的数据定义一个更为精细的接口,这将Strategy和Context更紧密的耦合在一起。

将Strategy作为模板参数

在C++中,可利用模板机制用一个Strategy来配置一个类。然而这种技术仅当下面条件满足时才可以使用:1,可以在编译时选择Strategy;2,它不需在运行时改变。在这种情况下,要被配置的类(如,Context)被定义为以一个Strategy类作为一个参数的模板类。
使用模板不在需要定义给Strategy定义接口的抽象类。把Strategy作为一个模板参数也使得可以将一个Strategy和它的Context静态地绑定在一起,从而提高效率。

使Strategy对象成为可选的

如果即使在不适用额外的Strategy对象的情况下,Context也还有意义的话,那么它还可以被简化。Context在访问某Strategy前先检查它是否存在,如果有,那么就是用它;如果没有,那么Context执行缺省的行为。这种方法的好处是客户根本不需要处理Strategy对象,除非它们不喜欢缺省的行为。

相关模式

Flyweight Pattern

ConcreteStrategy参与者有时会用到享元模式,让一个以上的位置能共享。Strategy对象经常是很好的轻量级对象

Abstract Factory Pattern

在策略模式中可以彻底切换算法,不留痕迹,抽象工程模式中是完整切换具体工程、零件或者产制品。

State Pattern

状态模式和策略模式都是切换委托对象的模式,类间的关系也很类似,但目的不同;策略模式是建立表示算法的类,把他设为Concrete Strategy。在策略模式中可以切换不同的类,不过如果没有必要,也可以不切换;而状态模式是建立状态的类,把他设为ConcreteState参与者,状态模式一遇到状态发生变化时,就一定会切换委托对象的类。
状态模式和策略模式区别关键是看行为是有状态驱动的还是算法驱动的;而且策略模式中的算法有客户端决定,并且不能中断,一次只能调用一个算法;而状态模式在生命周期中存在着状态的转换和行为的更改,而且状态的变换是一个线型的整体;对于客户程序来说这种状态变换往往是透明的。

敬请期待“状态模式(State Pattern,对象行为型模式)”

0 0