当你碰到几个对象是同一类对象,都有大致相同种类的行为,但是这些同类行为所造成的效果不同时,你就可以考虑策略模式来构建你的类关系了,善用策略模式会使你的代码耦合程度获得显著的降低。

首先我们先来举一个常见的例子来为讨论策略模式做一个铺垫:

class PhoneBelongToJack{ //杰克有一部手机
String ownerName = "Jack";
void ringtone(){
System.out.println("Old mobile phone ring"); //这部手机是Old手机
}

void systemName(){
System.out.println("I have no system"); //没有操作系统
}void rang(){
ringtone();systemName();
System.out.println("\n"+ ownerName +"! You have a phone call.");
}
 }

不幸的是这部Old手机很老了,于是,杰克买了一部Nokia N97。那么,现在问题来了,如果一旦有电话打进来,手机铃声仍然是Old手机铃声,操作系统仍然是No system,如何改变呢?

我们不得不删除原来的代码重新书写,这违反了OO设计原则之一——对扩展开放,对修改关闭。

但是,也许有人会说:“我可以继承PhoneBelongToJack类,覆盖掉老的ringtone(),systemName()方法。”这个人的代码是:

class NokiaPhone extends  PhoneBelongToJack{ 
void ringtone(){
System.out.println("Nokia mobile phone ring"); //这部手机是Nokia
}

void systemName(){
System.out.println("My system is  Symbian"); //  Symbian操作系统
}
 }

这算是一种解决方式,而且很传统和初级。但是这种方法仍然可以解决杰克又买了一部了iphone的问题,代码是这样的:

class IPhone extends PhoneBelongToJack{ 
 void ringtone(){
 System.out.println("Iphone mobile phone ring"); //这部手机是Iphone
 }

 void systemName(){
 System.out.println("My system is ios"); // ios操作系统
 }
 }

但是,事情往往没有那么容易,杰克是一名很没有品味的手机发烧友,他想要将iPhone手机的系统界面做成Symbian系统样式的,并且他居然还成功了。

一天,一个电话打进来,于是问题出现了!

杰克的iPhone的铃声是iPhone铃声,但是它的系统已经变成了“Symbian”系统,这怎么办呢?难道还要再弄一个子类出来?这显然不合适,

于是,我们看到继承并不是解决这类问题的合适方法。

正确的方法是结合“组合”、“委托”的思想和正确的OO设计原则——将变化从不变中分离出来/针对接口编程,不针对具体实现编程,利用“Strategy”模式来设计系统,重新设计的代码应该是这样的:

class PhoneBelongToJack{
private String ownerName = "Jack";
private RingTone ringTone ;         //将可变部分分离出来单独聚类成行为类接口
private SystemInPhone system ;    //将可变部分分离出来单独聚类成行为类接口



public PhoneBelongToJack(RingTone ringTone, SystemInPhone system) {   //针对接口编程的好处是:程序可以在运行时动态的选择行为的具体实现而不用写死在类中
super();
this.ringTone = ringTone;
this.system = system;
}

void ringtone(){       
ringTone.ringtone();       //将行为的执行委托给行为类对象完成,而本对象不关心行为的具体实现方式
}

void systemName(){
system.systemName();   //将行为的执行委托给行为类对象完成,而本对象不关心行为的具体实现方式
}

void rang(){
ringtone();
systemName();
System.out.println("\n"+ ownerName +"! You have a phone call.");
}
 }

 interface RingTone{         // 抽象出接口便于形成行为的“算法族”
void ringtone();
 }

 interface SystemInPhone{    // 抽象出接口便于形成行为的“算法族”
void systemName();
 }

 class OldRingTone implements RingTone{                 // 铃声这一“算法族”包含的铃声实现之一
public void ringtone(){
System.out.println("Old mobile phone ring"); 
}
 }

 class NokiaRingTone implements RingTone{  // 铃声这一“算法族”包含的铃声实现之一
public void ringtone(){
System.out.println("Nokia mobile phone ring"); 
}
 }

 class IphoneRingTone implements RingTone{  // 铃声这一“算法族”包含的铃声实现之一

@Override
public void ringtone() {
// TODO Auto-generated method stub
System.out.println("Iphone mobile phone ring"); 
}
 }

 class OldSystem implements SystemInPhone{  //  系统这一“算法族”包含的铃声实现之一
public void systemName(){
System.out.println("I have no system"); 
}
 

 class NokiaSystem implements SystemInPhone{  //  系统这一“算法族”包含的铃声实现之一
public void systemName(){
System.out.println("My system is Symbian"); 
}
 }

 class IphoneSystem implements SystemInPhone{  //  系统这一“算法族”包含的铃声实现之一
public void systemName(){
System.out.println("My system is ios"); 
}
 }

策略模式将可变化的对象行为作为对象的实例属性注入进对象,从而使对象获得灵活多变的行为表现。这样一来可变行为在产生变化时,只需将该行为实现为“算法族”的某一种行为,然后注入进对象之中即可,而不必改变原有封装的类的代码。