设计模式之策略模式

原创 2016年05月30日 13:31:39

设计模式之策略模式

博客地址

今天介绍下策略模式,直接先上UML图

enter image description here

策略模式的概念

The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
–(翻译)– 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。策略模式使得算法可独立于使用它的客户而变化。

1、需要使用ConcreteStrategy提供的算法。
2、 内部维护一个Strategy的实例。
3、 负责动态设置运行时Strategy具体的实现算法。
4、负责跟Strategy之间的交互和数据传递。

策略模式的组成

— Strategy(抽象策略类): 通常由一个接口或者抽象类实现。
— ConcreteStrategy(具体策略角色):包装了相关的算法和行为。一般有多个
— Context(环境角色):持有一个策略类的引用,最终给客户端调用。

策略模式的应用场景

定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。策略模式使得算法可独立于使用它的客户而变化。实际开发中用途,比如google开源的android网络框架volley,volley的超时重发重发机制就使用到了典型策略模式,看源码
RetryPolicy.java 请求重试策略类,定义了三个接口

package com.android.volley;

/**
 * 请求重试策略类
 * 此类属于抽象策略类对应Strategy
 */
public interface RetryPolicy {

    /**
     * 超时时间
     */
    public int getCurrentTimeout();

    /**
     * 重试次数
     */
    public int getCurrentRetryCount();

    /**
     * 针对错误异常的处理
     */
    public void retry(VolleyError error) throws VolleyError;
}

DefaultRetryPolicy.java 默认重试策略,继承了RetryPolicy ,具体实现了接口,我截取了部分代码

public class DefaultRetryPolicy implements RetryPolicy {
   ...
    public static final int DEFAULT_TIMEOUT_MS = 2500;
    private int mCurrentTimeoutMs;
    /** The default number of retries */
    public static final int DEFAULT_MAX_RETRIES = 0;

    /** The default backoff multiplier */
    public static final float DEFAULT_BACKOFF_MULT = 1f;

   ...//代表省略掉的代码

    @Override
    public int getCurrentTimeout() {
        return mCurrentTimeoutMs;
    }

    @Override
    public int getCurrentRetryCount() {
        return mCurrentRetryCount;
    }

    @Override
    public void retry(VolleyError error) throws VolleyError {
        mCurrentRetryCount++;
        mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
        if (!hasAttemptRemaining()) {
            throw error;
        }
    }
}

Request.java 请求类,持有一个抽象策略类RetryPolicy 的引用,最终给客户端调用。截取部分代码

public abstract class Request<T> implements Comparable<Request<T>> {
     private RetryPolicy mRetryPolicy; //持有策略类的引用

     ...

    public Request(int method, String url, Response.ErrorListener listener) {
        mMethod = method;
        mUrl = url;
        mIdentifier = createIdentifier(method, url);
        mErrorListener = listener;
        setRetryPolicy(new DefaultRetryPolicy());  //设置策略类

        mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
    }
    ...

     public Request<?> setRetryPolicy(RetryPolicy retryPolicy) {
        mRetryPolicy = retryPolicy;
        return this;
    }

    ...

    public final int getTimeoutMs() {
        return mRetryPolicy.getCurrentTimeout();
    }
}

BasicNetwork.java 网络处理类,处理Request,使用到了对应的重试策略,截取部分代码

/**
*遇到异常请求使用到了策略类的getTimeoutMs()方法
*/
private static void attemptRetryOnException(String logPrefix, Request<?> request,
            VolleyError exception) throws VolleyError {
        RetryPolicy retryPolicy = request.getRetryPolicy();
        int oldTimeout = request.getTimeoutMs();

        try {
            retryPolicy.retry(exception);
        } catch (VolleyError e) {
            request.addMarker(
                    String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
            throw e;
        }
        request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
    }

...

/**
* 网速慢,获取重试策略的重试次数getCurrentRetryCount
*/
 private void logSlowRequests(long requestLifetime, Request<?> request,
            byte[] responseContents, StatusLine statusLine) {
        if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {
            VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " +
                    "[rc=%d], [retryCount=%s]", request, requestLifetime,
                    responseContents != null ? responseContents.length : "null",
                    statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount());
        }
    }

...

 private static void attemptRetryOnException(String logPrefix, Request<?> request,
            VolleyError exception) throws VolleyError {
        RetryPolicy retryPolicy = request.getRetryPolicy();
        int oldTimeout = request.getTimeoutMs();

        try {
            retryPolicy.retry(exception);
        } catch (VolleyError e) {
            request.addMarker(
                    String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
            throw e;
        }
        request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
    }

实际使用中,我们可以自定义自己的策略继承RetryPolicy,这样就可以按照我们自己请求策略执行。

下面介绍一个比较简单的实例

自定义简单的策略模式实例

商品实现针对不同等级会员显示对应的会员价,比如一本书原价100元,一级会员打97折,三级会员打8折

PriceStrategy.java,策略类,可以使抽象类或接口,定义算法的公共接口,

/**
 * 定义一个计算价格的接口
 * 它属于抽象策略类
 * @author su
 */
public interface PriceStrategy {
    double priceStrategyInterface(double price);
}

SuperVipStrategy.java,超级会员算法,打八折,继承PriceStrategy

/**
 * 超级会员类
 * 它属于具体策略类,继承了计算价格接口
 * @author su
 *
 */
public class SuperVipStrategy implements PriceStrategy {

    @Override
    public double priceStrategyInterface(double price) {
        return price * 0.8; //打八折
    }
}

OneVipStrategy.java,一级会员算法,打九七折,继承PriceStrategy

/**
 * 一级会员类
 * 它属于具体策略类
 * @author su
 *
 */
public class OneVipStrategy implements PriceStrategy {
    @Override
    public double priceStrategyInterface(double price) {
        return 0.97 * price; //打九七折
    }
}

ThreeVipStrategy.java,三级会员算法,打九五折,继承PriceStrategy

/**
 * 三级会员商品类
 * 它属于具体策略类
 * @author su
 */
public class ThreeVipStrategy implements PriceStrategy {
    @Override
    public double priceStrategyInterface(double price) {
        return 0.95 * price; //九五折
    }
}

Price.java 上下文环境,持有PriceStrategy 的引用。

/**
 * 环境角色
 * @author su
 *
 */
public class Price {
    private PriceStrategy priceStrategy;
    public Price(PriceStrategy priceStrategy){
        this.priceStrategy = priceStrategy;
    }
    public double getVipPrice(double price){
        return priceStrategy.priceStrategyInterface(price);
    }
}

测试实例

public class Test {
    public static void main(String[] args){
        SuperVipStrategy supVipSrategy = new SuperVipStrategy();
        OneVipStrategy onVipStrategy = new OneVipStrategy();
        System.out.print("超级会员价="+new  Price(supVipSrategy).getVipPrice(100));
        System.out.print("一级员价="+new Price(onVipStrategy).getVipPrice(100));
    }
}

-----输出结果---
   超级会员价=80.0一级员价=97.0

实例的uml图
enter image description here

总结

优点

1、 提供了一种替代继承的方法,而且既保持了继承的优点(代码重用),还比继承更灵活(算法独立,可以任意扩展);
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展;
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合;
4、 易于进行单元测试,各个算法区分开,可以针对每个算法进行单元测试;

缺点

1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量;
2、 选择何种算法需要客户端来创建对象,增加了耦合,这里可以通过与工厂模式结合解决该问题;
3、 程序复杂化。

版权声明:本文为博主原创文章,转载请先注明出处

大话设计模式—策略模式

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。大话设计模式中程杰老师给出的定义是这样的:策略模式(Strategy),定义了...
  • lmb55
  • lmb55
  • 2016年03月23日 23:59
  • 1588

浅谈设计模式之简单工厂模式与策略模式

设计模式
  • hong_jing
  • hong_jing
  • 2016年09月01日 01:28
  • 296

23种经典设计模式之策略模式

前言 相信只要是学过java或者其他面向对象编程语言的伙伴们多少都听说过设计模式,比如可以说算是烂大街的mvc、单例模式都是其中之一。当然设计模式的家族很庞大,远远不止这些。那设计模式是用来干什么的呢...
  • ahzpc007
  • ahzpc007
  • 2016年11月03日 16:24
  • 774

设计模式之桥梁模式和策略模式的区别

桥接(Bridge)模式是结构型模式的一种,而策略(strategy)模式则属于行为模式。以下是它们的UML结构图。 桥梁模式: 策略模式: 在桥接模式中,Abstraction通过聚合的...
  • xingjiarong
  • xingjiarong
  • 2015年12月16日 21:57
  • 2676

设计模式C++实现——策略模式

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。         策略模式UML图如下:           举例:         游泳池中有不...
  • walkerkalr
  • walkerkalr
  • 2014年06月04日 15:32
  • 1388

python设计模式之策略模式

策略模式Strategy 模式和抽象工厂可能最难分辨,抽象工厂帮助我们根据我们的参数找到对应的操作工厂,而每个操作工厂提供了相同的接口函数 操作工厂所以可能是从一个基类继承的不同实现,举个例子,有个鸭...
  • leongongye
  • leongongye
  • 2015年07月29日 18:18
  • 359

设计模式--spring源码中使用策略模式(Strategy Pattern)

策略模式(Strategy Pattern)中体现了两个非常基本的面向对象设计的基本原则:封装变化的概念;编程中使用接口,而不是对接口实现。策略模式的定义如下: 定义一组算法,将每个算法都封装起...
  • a137268431
  • a137268431
  • 2016年07月04日 17:32
  • 1232

Android开发中无处不在的设计模式——策略模式

这个系列停更了好久了,差不多可以重新拿起来更一篇了,这篇文章主要介绍策略模式。在这之前,先温习一下前面介绍的4种模式。设计模式很重要! 设计模式很重要! 设计模式很重要!重要的事说三遍!!! An...
  • sbsujjbcy
  • sbsujjbcy
  • 2015年11月16日 11:50
  • 5316

scala设计模式

本文展示了一些经典的软件设计模式在Scala中的实现。        所谓设计模式,就是针对在软件设计过程中出现的一些共性问题,从而产生的一种可重用的解决方案。设计模式不是已完成的代码,而更像是...
  • xiao_jun_0820
  • xiao_jun_0820
  • 2015年02月28日 17:42
  • 1033

设计模式_改进策略模式_策略模式与简单工厂模式结合(Java)

上一篇我们介绍了《设计模式_策略模式(Java)》,同时讲述了策略模式与状态模式的区别,如果仔细查看代码或者类图,我们会发现策略模式在一定程度上是存在缺陷的,Client(Test类)必须知道所有的策...
  • tb3039450
  • tb3039450
  • 2016年09月22日 20:00
  • 1067
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:设计模式之策略模式
举报原因:
原因补充:

(最多只允许输入30个字)