[转载]策略模式-3

[转载]策略模式-3 – 云飞龙行 – 博客园.

3  模式讲解

3.1  认识策略模式

(1)策略模式的功能
策略模式的功能是把具体的算法实现,从具体的业务处理里面独立出来,把它们实现成为单独的算法类,从而形成一系列的算法,并让这些算法可以相互替换。
策略模式的重心不是如何来实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活、具有更好的维护性和扩展性。
(2)策略模式和if-else语句
看了前面的示例,很多朋友会发现,每个策略算法具体实现的功能,就是原来在if-else结构中的具体实现。
没错,其实多个if-elseif语 句表达的就是一个平等的功能结构,你要么执行if,要不你就执行else,或者是elseif,这个时候,if块里面的实现和else块里面的实现从运行 地位上来讲就是平等的。
而策略模式就是把各个平等的具体实现封装到单独的策略实现类了,然后通过上下文来与具体的策略类进行交互。
因此多个if-else语句可以考虑使 用策略模式。
(3)算法的平等性
策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正是因为这个平等性,才能实现算法之间可以相互替 换。
所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。
所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现
(4)谁来选择具体的策略算法
在策略模式中,可以在两个地方来进行具体策略的选择。
一个是在客户端,在使用上下文的时候,由客户端来选择具体的策略算法,然后把这个策略算法设置给上下文。前面的示例就是这种情况。
还有一个是客户端不管,由上下文来选择具体的策略算法,这个在后面讲容错恢复的时候给大家演示一下。
(5)Strategy的实现方式
在前面的示例中,Strategy都是使用的接口来定义的,这也是常见的实现方式。但是如果多个算法具有公共功能的话,可以把Strategy实现成为抽 象类,然后把多个算法的公共功能实现到Strategy里面。
(6)运行时策略的唯一性
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态的在不同的策略实现中切换,但是同时只能使用一个。

(7)增加新的策略
在前面的示例里面,体会到了策略模式中切换算法的方便,但是增加一个新的算法会怎样呢?比如现在要实现如下的功能:对于公司的“战略合作客户”,统一8 折。
其实很简单,策略模式可以让你很灵活的扩展新的算法。具体的做法是:先写一个策略算法类来实现新的要求,然后在客户端使用的时候指定使用新的策略算法类就 可以了。
还是通过示例来说明。先添加一个实现要求的策略类,示例代码如下:

/**

* 具体算法实现,为战略合作客户客户计算应报的价格

*/

public class CooperateCustomerStrategy implements Strategy{

public double calcPrice(double goodsPrice) {

System.out.println(“对于战略合作客户,统一8折”);

return goodsPrice*0.8;

}

}

然后在客户端指定使用策略的时候指定新的策略算法实现,示例如下:

public class Client2 {

public static void main(String[] args) {

//1:选择并创建需要使用的策略对象

Strategy strategy = new CooperateCustomerStrategy ();

//2:创建上下文

Price ctx = new Price(strategy);

//3:计算报价

double quote = ctx.quote(1000);

System.out.println(“向客户报价:”+quote);

}

}

除了加粗部分变动外,客户端没有其他的变化。

运行客户端,测试看看,好好体会一下。
除了客户端发生变化外,已有的上下文、策略接口定义和策略的已有实现,都不需要做任何的修改,可见能很方便的扩展新的策略算法。
(8)策略模式调用顺序示意图
策略模式的调用顺序,有两种常见的情况,一种如同前面的示例,具体如下:

a:先是客户端来选择并创建具体的策略对象

b:然后客户端创建上下文

c:接下来客户端就可以调用上下文的方法来执行功能了,在调用的时候,从客户端传入算法需要的参数

d:上下文接到客户的调用请求,会把这个请求转发给它持有的Strategy

这种情况的调用顺序示意图如图3所示:

图3  策略模式调用顺序示意图一

策略模式调用还有一种情况,就是把Context当做参数来传递给Strategy,这种方式的调用顺序图,在讲具体的Context和 Strategy的关系时再给出。

3.2  容错恢复机制

容错恢复机制是应用程序开发中非常常见的功能。那么什么是容错恢复呢?简单点说就是:程序运行的时候,正常情况下应该按照某种方式来做,如果按照某种方式 来做发生错误的话,系统并不会崩溃,也不会就此不能继续向下运行了,而是有容忍出错的能力,不但能容忍程序运行出现错误,还提供出现错误后的备用方案,也 就是恢复机制,来代替正常执行的功能,使程序继续向下运行。
举个实际点的例子吧,比如在一个系统中,所有对系统的操作都要有日志记录,而且这个日志还需要有管理界面,这种情况下通常会把日志记录在数据库里面,方便 后续的管理,但是在记录日志到数据库的时候,可能会发生错误,比如暂时连不上数据库了,那就先记录在文件里面,然后在合适的时候把文件中的记录再转录到数 据库中。
对于这样的功能的设计,就可以采用策略模式,把日志记录到数据库和日志记录到文件当作两种记录日志的策略,然后在运行期间根据需要进行动态的切换。
在这个例子的实现中,要示范由上下文来选择具体的策略算法,前面的例子都是由客户端选择好具体的算法,然后设置到上下文中。
下面还是通过代码来示例一下。
(1)先定义日志策略接口,很简单,就是一个记录日志的方法,示例代码如下:

/**

* 日志记录策略的接口

*/

public interface LogStrategy {

/**

* 记录日志

* @param msg 需记录的日志信息

*/

public void log(String msg);

}

(2)实现日志策略接口,先实现默认的数据库实现,假设如果日志的长度超过长度就出错,制造错误的是一个最常见的运行期错误,示例代码如 下:

/**

* 把日志记录到数据库

*/

public class DbLog implements LogStrategy{

public void log(String msg) {

//制造错误

if(msg!=null && msg.trim().length()>5){

int a = 5/0;

}

System.out.println(“现在把 ‘”+msg+”‘ 记录到数据库中”);

}

}

接下来实现记录日志到文件中去,示例代码如下:

/**

* 把日志记录到文件

*/

public class FileLog implements LogStrategy{

public void log(String msg) {

System.out.println(“现在把 ‘”+msg+”‘ 记录到文件中”);

}

}

(3)接下来定义使用这些策略的上下文,注意这次是在上下文里面实现具体策略算法的选择,所以不需要客户端来指定具体的策略算法了,示例代码如下:

(4)看看现在的客户端,没有了选择具体实现策略算法的工作,变得非常简单,故意多调用一次,可以看出不同的效果,示例代码如下:

(5)小结一下,通过上面的示例,会看到策略模式的一种简单应用,也顺便了解一下基本的容错恢复机制的设计和实现。在实际的应用中,需要设计容错 恢复的系统一般要求都比较高,应用也会比较复杂,但是基本的思路是差不多的。

未完待续……

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏