策略模式用于抽象对于同一个对象的不同处理方式,把相同处理方式(内部状态)抽象成一个类,通过策略选择类选择产生对应的策略来处理输入的对象。
换个角度想想,其实策略模式需要结合简单工厂模式一起使用,是一种进化版的简单工厂类。可以说策略模式是实现简单工厂模式的一种必要。就像直接把计算器的不同算法加减乘除封装成对象,这其实就是策略模式,再通过简单工厂类中的判断,返回不同的策略对象。(P.S. 工厂方法是把返回加减乘除的不同工厂封装成对象。)
然而,策略模式的厉害之处在于其能更好的封装内部处理和与客户端代码更好的解耦。关键在于创建的策略选择类。先来看总图:
策略选择类就是Context。
让我们简单工厂方法的例子为代码,说说怎么更好的与客户端解耦:
首先,还是照常地定义策略类的抽象类(或者接口)和不同的策略实现类,其实也就是运算符类的接口和运算符的实现类:
interface Operation{
int calculateResult(int a, int b);
}
class OperationAdd implements Operation{
public int calculateResult(int a, int b){
return a+b;
}
}
接着,定义一个Context类:
<pre name="code" class="java"><pre name="code" class="java">public class Context{
public static int getResult(Operation ins, int a, int b){
return ins.calculateResult(a,b);
}
}
因为客户端还是需要知道有哪些运算类,然后根据用户输入,产生对应的运算类的对象,然后再调用context内。这样,客户端代码就包含冗余的代码了。所以,我们可以结合工厂代码,把所有的判断、计算都包含在Context内做:
public class Context{
public int getResult(String s, int a, int b){
switch(s){
case "add": return Context.getResult(new OperationAdd, a, b);break;
case "minus": return Context.getResult(new, OperationMinus, a, b);break;
......
}
}
private static int getResult(Operation ins, int a, int b){
return ins.calculateResult(a,b);
}
}
这样,我们的客户端代码可以变为:
public class Customer{
public static void main(Strings args[]){
Context ins = new Context();
int result ins.getResult("add",1,2);
}
}
对比之前简单工厂模式的客户端代码:
public static void main(String[] args){
Operation op = SimpleFactory.getOperation("+");
int result = op.calculateResult(1,1);
}
我们可以发现,现在连抽象类或者说接口Operation都不需要让客户端知道了。这样子的解耦,就更彻底了。
而适配器模式,其实我更喜欢把它叫做翻译模式。它能让接口不同(方法名不同)但功能相似的两个类,通过一个翻译类,使得能通过一个类的接口(语言)去指挥另一个类去干功能相似的事情。适配器模式的出现,动机是为了两个实现不同接口然而功能相近的类,能以同一个接口去调用它们去实现相近的功能。这种模式在现实的软件设计中十分有用,在别人的库函数已经写好了,你只能调用的情况下,你发现,来自于两个不同的库有两个类,它们其实某些方法实现的功能类似,譬如都是实现傅里叶变换,但一个类是离散信号类的,它的傅里叶变换的函数是:fTrans_Func(Wave input),而另一个是连续信号类的,它的傅里叶变换函数是: fTrans(Wave input)。我想用统一的接口调用这两个函数的话,假设我想用离散信号的接口来调用连续信号的函数,而离散信号类有一个父类接口是信号类,其定义为:
interface Signal{
Wave fTrans_Func(Wave input);
}
public class continuedSignalAdapter implements Signal{
private continuedSignal = new continuedSignal;// 用来调用fTrans
public Wave fTrans_Func(Wave input){
return continuedSignal.fTrans(input);
}
}
这样,就能实现以相同的接口调用两个类的相似的方法了。
之前我还写过一篇关于适配器的博客,可以参考: http://blog.csdn.net/Firehotest/article/details/51993922
里面的一幅来自《大话设计模式》的图也很好的解释了适配器模式。