策略(Strategy)模式

  策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响客户端的情况下发生变化。

  策略模式相当于可插入式的算法。可以使得在保持接口不变的情况下,使具体算法可以互换。

1.  简介

  策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。也就是说:准备一组算法,并将每一个算法封装起来,使得它们可以互换。

  简略类图如下:

  

2.  结构

  策略又称作政策(Policy)模式。其结构如下:

这个模式涉及到三个角色:

(1)环境(Context)角色:持有一个Strategy的引用

(2)抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或者抽象类实现。此角色给出所有的具体策略类的接口。

(3)具体策略(ConcreteStrategy)类,包装了相关的算法或者行为。

伪代码如下:

package cn.qlq.strategy;

public class Context {

    private Strategy strategy;

    public void contextInterface() {
        strategy.strategyInterface();
    }

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

}
package cn.qlq.strategy;

public interface Strategy {

    void strategyInterface();
}
package cn.qlq.strategy;

public class ConcreteStrategy implements Strategy {

    @Override
    public void strategyInterface() {
        System.out.println("具体的算法逻辑");
    }

}

  一般而言,有意义的策略模式的应用会涉及多于一个的具体策略角色。上面的代码可以作为一个策略模式的骨架。

3.  模式的实现

注意的地方:

(1)所有的具体策略类都有一些公有的行为。这时候就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。这时候抽象策略角色必须用抽象类实现而不能使用接口。

(2)策略模式在每一个时刻都只能使用一个策略对象,但是有的时候一个应用程序同时与几个策略对象相联系。换言之,在应用程序启动时,所有的策略对象就已经被创立出来,而应用程序可以在几个策略对象之间调换。这只有在策略对象不会耗费很多计算机内存资源的情况下才可行,只有在策略对象初始化会花费很长时间的情况下才需要。

假设现在要设计一个贩卖各类书籍的电子商务网站的购物车系统。网站内的所有图书可能有折扣,大致分为:没有折扣、标价上面减去定额2元、按3%比例折扣。

使用策略模式描述的话这些不同的算法都是不同的具体策略角色:NoDiscountStrategy表示算法一;FlatDiscountStrategy表示算法二;PercentageStrategy表示算法三。

类图如下:

代码如下:

package cn.qlq.strategy;

public abstract class DiscountStrategy {

    /**
     * 单价
     */
    protected float price;

    /**
     * 数量
     */
    protected int numbers;

    abstract float calculateDiscount();

    public DiscountStrategy(float price, int numbers) {
        super();
        this.price = price;
        this.numbers = numbers;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    public int getNumbers() {
        return numbers;
    }

    public void setNumbers(int numbers) {
        this.numbers = numbers;
    }

}

  这个是一个抽象类,而抽象类不可能有实例。上面的两个属性以及构造子是为了约束具体策略类应当赋值给单价和数量,然后调用 calculateDiscount 算出折扣。

package cn.qlq.strategy;

public class NoDiscountStrategy extends DiscountStrategy {

    public NoDiscountStrategy(float price, int numbers) {
        super(price, numbers);
    }

    @Override
    float calculateDiscount() {
        return 0;
    }

}
package cn.qlq.strategy;

public class FlatDiscountStrategy extends DiscountStrategy {

    /**
     * 折扣金额
     */
    private float discountAmount;

    public FlatDiscountStrategy(float price, int numbers, float discountAmount) {
        super(price, numbers);

        this.discountAmount = discountAmount;
    }

    @Override
    float calculateDiscount() {
        return discountAmount * numbers;
    }

    public float getDiscountAmount() {
        return discountAmount;
    }

    public void setDiscountAmount(float discountAmount) {
        this.discountAmount = discountAmount;
    }

}
package cn.qlq.strategy;

public class PercentageStrategy extends DiscountStrategy {

    /**
     * 折扣比例
     */
    private float discountPercent;

    public PercentageStrategy(float price, int numbers, float discountPercent) {
        super(price, numbers);

        this.discountPercent = discountPercent;
    }

    @Override
    float calculateDiscount() {
        return discountPercent * price * numbers;
    }

    public float getDiscountPercent() {
        return discountPercent;
    }

    public void setDiscountPercent(float discountPercent) {
        this.discountPercent = discountPercent;
    }

}

何时使用何种策略?

  策略模式并不负责决定使用哪个具体策略,这种决定应该由客户端决定。策略模式仅仅封装算法。而且客户端在使用不同的策略模式的同时需要了解不同策略模式需要的参数。

  测试模式不适合于处理同时嵌套多于一个算法的清形。一般而言,策略模式只适用于在几种算法中选择一种。

  比如在上面基础增加了第四种法则:在所有的折扣算法计算后,总的折扣不能超过1000。这也就意味着客户端需要使用上面算法一、二、三计算出折扣总值,再使用算法四。这就需要再借助于装饰者模式

4.  适用场景与优缺点

1.  适用场景

在下面的场景下应当使用策略模式:

(1)一个系统有许多类,它们之间的区别仅在于它们的行为。

(2)一个系统中需要动态地在几种算法中选择一种。

(3)一个算法使用的数据不需要客户端知道

(4)一个对象有多种行为,如果不用恰当的模式就只能使用多重的条件选择语句来实现。此时,用策略模式可以避免难以维护的多重选择,并体现面向对象的思想。

2.  优点:

(1)策略模式提供了管理相关算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类中,从而避免重复的代码。

(2)策略模式提供了可以替换继承关系的办法。继承使得动态改变算法或行为变得不可能。

(3)使用策略模式可以避免使用多重条件判断语句。

3.  缺点:

(1)客户端必须知道所有的具体策略类,并自行决定使用哪种策略类。

(2)策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端,而将策略类设计成可共享的。这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。

5.  操作系统中的策略模式-windows屏幕保护程序的设置

  每一个屏幕保护程序都有不同的参数设置,如下:

  每一种程序提供不同的算法,在屏幕上放映3D文字、图片等。用户需要为每一种程序设定所需的参数。策略模式提供了解决这个问题的方案。当用户选中一个屏幕保护程序后就需要设定程序的参数。如下是3D文字所需要的参数:

  这是典型的策略模式的应用:每一个屏幕保护程序都有一个自己的参数设定窗口。这个窗口便是具体策略角色,它代表不同的算法;用户可以选择一个算法并设定其参数;所有的参数设定窗口都有自恰的界面设计,让用户相信策略对象后面有一个共同的抽象接口约束它们,它就是抽象策略角色。

原文地址:https://www.cnblogs.com/qlqwjy/p/11238682.html

时间: 2024-10-24 10:32:57

策略(Strategy)模式的相关文章

C++设计模式实现--策略(Strategy)模式

一. 举例说明 以前做了一个程序,程序的功能是评价几种加密算法时间,程序的使用操作不怎么变,变的是选用各种算法. 结构如下: Algorithm:抽象类,提供算法的公共接口. RSA_Algorithm:具体的RSA算法. DES_Algorithm:具体的DES算法. BASE64_Algorithm:具体的Base64算法. 在使用过程中,我只需要对外公布Algorithm_Context这个类及接口即可. 代码实现: [cpp] view plaincopy //策略类 class Alg

Java 实现策略(Strategy)模式

策略模式:行为型模式 将同一行为,不同的处理算法分别封装起来.让它们之间能够互相替换 1. 定义一个超类型接口,及 行为方法 2. 定义不同的实现类,实现该行为的 不同的算法 /** * 策略模式:针对同一命令(或行为),不同的策略做不同的动作 * 商品促销 * 本类为:收取现金的类 * * @author stone */ public interface ICashSuper { double acceptCash(double money); } /** * 正常收取现金 * @autho

设计模式之策略(Strategy)模式

Strategy模式是一种行为型设计模式,它将算法一个个封装起来,在某一时刻能够互换地使用其中的一个算法.从概念上看,所有这些算法完成的都是相同的工作,只是实现不同而已. 动机 在开发中,我们常常会遇到概念上相同,处理方法不同的任务,例如,对一件商品使用不同的税额计算方法来计算其价格.一般来说,有以下的方法来处理: 复制和粘贴(一份代码具有两个版本,维护成本大) 使用switch或者if语句,用一个变量指定各种情况(分支会变得越来越长) 函数指针或者委托(无法维持对象的状态) 继承(需求变化时,

Java设计模式之从[剪刀石头布AI策略]分析策略(Strategy)模式

策略模式是一个很easy的模式. 它定义一系列的算法,把它们一个个封装起来,而且使它们能够相互替换. 考虑到我在做一个剪刀石头布的游戏,能够和计算机对战. 计算机的难度等级分为2个等级:普通难度和无法战胜难度. 普通难度是指电脑会随机出石头.剪刀.布.而无法战胜难度是指电脑会"作弊".电脑会事先知道玩家出的是什么手势. 假设玩家出的是剪刀.那么电脑会出石头,玩家永远的无法取胜. 那么,这两个难度分别代表两种算法,为了使得它们可以被游戏的主类装载,它们都应该继承于同一个接口或类.并暴露出

《Head First 设计模式》ch.1 策略(Strategy)模式

策略模式 定义了算法族,分别封装起来,让它们可以互相替换,让算法的变化独立于使用算法的客户. 模式名词的意义 威力强大,交流的不止是模式名称,而是一整套模式背后所象征的质量.特性.约束 用更少的词汇做更充分的沟通 保持在设计层次,不会被压低到类与对象这种琐碎的事情上 帮助初级开发人员迅速成长

C#设计模式-策略者模式(Strategy)

策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象管理.策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类.用一句话来说,就是:"准备一组算法,并将每一个算法封装起来,使得它们可以互换." 模式涉及到三个角色: 1.环境(Context)角色:持有一个Strategy类的引用.

Java策略模式(Strategy模式) 之体验

<JAVA与模式>之策略模式 在阎宏博士的<JAVA与模式>一书中开头是这样描述策略(Strategy)模式的: 策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 策略模式的结构 策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理.策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类.用一句话来说,就

Strategy(策略)模式

1.概述 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查找.排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法:当然也可以将这些查找算法封装在一个统一的方法中,通过if…else…或者case等条件判断语句来进行选择.这两种实现方法我们都可以称之为硬编码,如果需要增加一种新的查找算法

JAVA设计模式十--strategy(策略者模式)

概念策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化.(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makesthem interchangeable. Strategy lets the algorithm vary independently from clients that use it.)Conte