算法是定义好的过程,它能够根据一组输入产生一个输出.而策略是一个计划,它也涉及如何从一组输入获得一组输出.在通常情况下,与算法相比,策略是能够提供更大范围的可选方案.因而,策略通常代表一组或者一簇可以相互替换的方案.
当计算机程序存在多种策略时,程序代码会比较复杂.当有多个策略可用时,与策略相关的程序逻辑必须选择其中一个策略来执行,这时策略选择的程序代码可能变得很复杂,同时策略使用的逻辑通常也比较复杂.我们可以使用Strategy模式来整理这些代码.
策略操作定义了策略的输入和输出,而把策略的实现工作留给各个类。这些类以不同的方案来实现同一个操作,它们为用户提供统一的接口,因而这些类可以相互替换。Strategy模式允许多种策略共存,而代码不会混乱。策略模式也可以实现模式选择逻辑和策略本身相分离。
Strategy模式的意图在于把可选的策略或方案封装在不同的类中,并在这些类中实现一个共同的操作。
1.策略建模:
Strategy模式把问题的不同解决方法封装在不同的类中,有助于组织和简化代码。先来看看不使用Strategy模式情况下策略的建模方式:
现在思考一下Oozinoz公司的焰火制品推销广告策略。当客户访问Oozinoz公司的网站或给公司呼叫中心打电话时,客户会获得一些有关购买焰火制品的建议。Oozinoz公司使用了两个现有的推荐引擎来向客户推荐合适的焰火制品。Customer类选择并应用其中的一个引擎来决定应该向客户推荐哪种焰火制品。
Rel8引擎是其中的一个推荐引擎,它能够根据客户之间的相似性来向客户推荐焰火制品.在使用这种引擎之前,客户必须进行注册,并且给出一些诸如他对焰火和其他娱乐活动的喜好或厌恶等信息.
如果客户没有注册,Oozinoz公司则使用另一个名为LikeMyStuff的推荐引擎,这个引擎能够根据客户最近的购买信息向其进行推荐.如果对这两种引擎都没有提供足够的信息,该推销软件将随机选择一种焰火向客户推荐.不过,如果Oozinoz公司希望推销某种焰火制品,那么这种焰火制品将会俦被推销,而不考虑前面的因素.图1所示的各个类相互协作,从而实现向客户推荐焰火制品的行为.
LikeMyStuff和Rel8引擎分别接收一个Customer对象,并将某种焰火制品推荐给这个客户.在利用两个引擎推荐焰火制品之前,我们必须对它们进行配置.不过,LikeMyStuff需要一个数据库,而Rel8则完全依赖于对象模型.Customer类的getRecommend()方法实现了Oozinoz公司的焰火制品推销广告策略:
public Firework getRecommended() {
// if we're promoting a particular firework, return it
try {
Properties p = new Properties();
p.load(ClassLoader.getSystemResourceAsStream("config/strategy.dat"));
String promotedName = p.getProperty("promote");
if (promotedName != null) {
Firework f = Firework.lookup(promotedName);
if (f != null) return f;
}
} catch (Exception ignored) {
// If resource missing or it failed to load,
// fall through to the next approach.
}
// if registered, compare to other customers
if (isRegistered()) {
return (Firework) Rel8.advise(this);
}
// check spending over the last year
Calendar cal = Calendar.getInstance();
cal.add(Calendar.YEAR, -1);
if (spendingSince(cal.getTime()) > 1000) return (Firework) LikeMyStuff.suggest(this);
// oh well!
return Firework.getRandom();
}
getRecommended()方法希望如果在促销焰火制品时,将焰火制品的名称保存在config目录下的strategy.dat文件中.
protmote = JSquirrel
如果没有类似这样的文件,并且客户已经注册,则getRecommended()方法会使用Rel8引擎,如果没有促销焰火制品,客户没有注册,并且客户在本系统中留有以前的购买记录,则getRecommended()方法会使用LIkeMyStuff引擎.如果客户既没有注册,也不是大客户,上面的代码则会随机选择一种焰火制品推荐给他.getRecommended()方法的确可以起作用,并且这段代码写得并不是很糟糕.不过,我们还可以让它变得更好.

Customer类依赖于其他的类来获取将被推荐的焰火制品,其中包括两个现有的推荐引擎
本文探讨了策略模式在代码组织中的应用,通过Oozinoz公司推销焰火制品的案例,详细介绍了如何使用策略模式来封装不同的算法或策略,使程序更加灵活且易于维护。

437

被折叠的 条评论
为什么被折叠?



