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

策略模式的概念

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 请求重试策略类,定义了三个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.android.volley;

/**
* 请求重试策略类
* 此类属于抽象策略类对应Strategy
*/
public interface RetryPolicy { /**
* 超时时间
*/
public int getCurrentTimeout(); /**
* 重试次数
*/
public int getCurrentRetryCount(); /**
* 针对错误异常的处理
*/
public void retry(VolleyError error) throws VolleyError;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 的引用,最终给客户端调用。截取部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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,使用到了对应的重试策略,截取部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
*遇到异常请求使用到了策略类的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,策略类,可以使抽象类或接口,定义算法的公共接口,

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 超级会员类
* 它属于具体策略类,继承了计算价格接口
* @author su
*
*/
public class SuperVipStrategy implements PriceStrategy { @Override
public double priceStrategyInterface(double price) {
return price * 0.8; //打八折
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 一级会员类
* 它属于具体策略类
* @author su
*
*/
public class OneVipStrategy implements PriceStrategy {
@Override
public double priceStrategyInterface(double price) {
return 0.97 * price; //打九七折
}
}

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

1
2
3
4
5
6
7
8
9
10
11
/**
* 三级会员商品类
* 它属于具体策略类
* @author su
*/
public class ThreeVipStrategy implements PriceStrategy {
@Override
public double priceStrategyInterface(double price) {
return 0.95 * price; //九五折
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 环境角色
* @author su
*
*/
public class Price {
private PriceStrategy priceStrategy;
public Price(PriceStrategy priceStrategy){
this.priceStrategy = priceStrategy;
}
public double getVipPrice(double price){
return priceStrategy.priceStrategyInterface(price);
}
}

测试实例

1
2
3
4
5
6
7
8
9
10
11
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图

总结

优点

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

缺点

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

Android设计模式之策略模式的更多相关文章

  1. 设计模式:策略模式(Strategy)

    定   义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...

  2. PHP设计模式之策略模式

    前提: 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查 找.排序等,一种常用的方法是硬编码(Hard Cod ...

  3. JavaScript设计模式之策略模式(学习笔记)

    在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选 ...

  4. 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)

    原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...

  5. JavaScript设计模式之策略模式

    所谓"条条道路通罗马",在现实中,为达到某种目的往往不是只有一种方法.比如挣钱养家:可以做点小生意,可以打分工,甚至还可以是偷.抢.赌等等各种手段.在程序语言设计中,也会遇到这种类 ...

  6. Android 设计模式之MVC模式

    说到Android设计模式的MVC模式,估计很多人都是比较熟悉了,这里深入了解一下MVC到底是怎么回事,以ListView为例子讲解. 一.深入理解MVC概念 MVC即Model-View-Contr ...

  7. 【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查

    原文:使用模板方法设计模式.策略模式 处理DAO中的增删改查 关于模板模式和策略模式参考前面的文章. 分析 在dao中,我们经常要做增删改查操作,如果每个对每个业务对象的操作都写一遍,代码量非常庞大. ...

  8. [design-patterns]设计模式之一策略模式

    设计模式 从今天开始开启设计模式专栏,我会系统的分析和总结每一个设计模式以及应用场景.那么首先,什么是设计模式呢,作为一个软件开发人员,程序人人都会写,但是写出一款逻辑清晰,扩展性强,可维护的程序就不 ...

  9. 设计模式入门,策略模式,c++代码实现

    // test01.cpp : Defines the entry point for the console application.////第一章,设计模式入门,策略模式#include &quo ...

随机推荐

  1. Linux网络编程4——个人总结

    TCP与UDP通信流程 TCP通信的基本步骤如下: 服务端:socket---bind---listen---while(1){---accept---recv---send---close---}- ...

  2. sql只修改第一二行数据

    update t_table set colname=*  where a=1 order by id desc limit 1,2

  3. YARN集群维护部分问题汇总

    云梯开发人员在云梯Yarn集群的搭建和维护过程中做了许多工作,本文选择这期间部分较为典型的问题,通过对这些问题的分析和解决方案,为大家分享分布式系统问题调查的经验. 调查的问题 1. 2013年初引入 ...

  4. OSVERSIONINFO的用法及实例

    OSVERSIONINFO 快速信息 Windows NT   支持 Windows 95    支持 Win32s           支持 引入程序库    - 头文件           win ...

  5. Project Euler 103:Special subset sums: optimum 特殊的子集和:最优解

    Special subset sums: optimum Let S(A) represent the sum of elements in set A of size n. We shall cal ...

  6. 重温《js权威指南》 第4、5、6章

    第四章 表达式和运算符         4.2 对象和数组的初始化表达式                数组: []   [3,7] [1+2,3+4] [[1,2,3,],[4,5,6],[7,8, ...

  7. Docker搭建MySQL服务

    Docker开源镜像 前面我们已经安装好了Docker,也简单了解了Docker.那么我们可以尝试搭建一个MySQL服务. 要搭建服务就要启动服务容器,要创建容易就要有镜像,Docker提供了一个类似 ...

  8. oracle记录解锁

    oracle 怎样查一个表中的记录是否被锁住了   怎么查询一个数据库中有几个表引用了其中某个特定表的主键做为其外键的select t.table_name from user_constraints ...

  9. Oracle ->> 层级查询语句(hierarchical query)connect by

    Oracle中的Connect By... Start With语句实现了递归查询或者树状查询. Connect By Prior 一方为起始(root)的ID 参考: http://www.360d ...

  10. Activity 跳转动画 全局定义

    定义application 的 theme <application android:allowBackup="true" android:icon="@drawa ...