继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Android设计模式之策略模式

桃花长相依
关注TA
已关注
手记 113
粉丝 15
获赞 56

今天介绍下策略模式

策略模式的概念

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

总结

优点

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

缺点

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

原文链接:http://www.apkbus.com/blog-705730-61218.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP