策略模式定义了一些算法族,并分别将其封装起来,让它们之间可以互相替换,该模式可以将算法的变化独立于使用算法的用户。定义这东西一般都比较抽象,希望下文能够有助理解。。。
算法族,其实就是一组行为类,比如下面例子中的实现接口 IEatBehavior 的一组类(WhiteCatEatBehavior,BlackCatEatBehavior );可以互相替换:可以在运行时动态替换行为(这个也是组合的一大优点),当然,前提是替换和被替换的行为类实现的是同一个接口;独立于使用算法的用户,因为该模式将变化的部分封装起来,所以可以独立于使用算法的用户。如果还是觉得有点抽象,那就继续往下看吧。。。(看完下面的例子,再看看上面的文字描述,理解起来可能会稍容易一些)
代码示例:
创建一个抽象类(Cat),和一个继承它的子类
public abstract class Cat
{
public void Eat()
{
System.Out.Println(" I Eat Mouse.");
}
public void Walk()
{
System.Out.Println(" I Walk With My Feet.");
}
}
public class WhiteCat Extends Cat {}
在这个类中,假设Eat()方法是需要变化的部分(不是所有的猫都吃老鼠的。。。),而Walk()方法是不需要变化的部分(一般情况下,应该都是用脚走路的吧),按照上面的设计原则,应该把Eat()方法给独立出去封装起来,but how...试试接口吧,下面我们就来新建一个含有Eat()方法的接口。
public interface IEatBehavior
{
public Eat();
}
OK,接口建好了,现在得实现 Eat()这个方法了,即新建一些具体类。(接口中的方法只需要定义,而不需要实现,用户只需要知道该接口可以做什么,而不需要知道怎么做)
public class WhiteCatEatBehavior implements IEatBehavior
{
public void Eat()
{
System.Out.Println(" I Eat Mouse.");
}
}
public class BlackCatEatBehavior implements IEatBehavior
{
public void Eat()
{
System.Out.Println(" I Eat Fish.");
}
}
现在让我们利用策略模式重新写一下 Cat 类吧
public abstract class Cat
{
// 为行为接口定义一个引用变量
IEatBehavior pEatBehavior;
public void Eat()
{
// 在这 Cat 不再亲自处理,而是委托给IEatBehavior 对象处理
pEatBehavior.Eat();
}
public void Walk()
{
System.Out.Println(" I Walk With My Feet.");
}
}
public class WhiteCat Extends Cat
{
public WhiteCat()
{
// 因为WhiteCat继承自Cat,所以Cat中的成员及方法,WhiteCat中都有,
// 在构造器中,白猫使用WhiteCatEatBehavior处理Eat()方法,
// 所以当Eat()被调用时,吃的职责被委托给WhiteCatEatBehavior对象
pEatBehavior = new WhiteCatEatBehaviorClass();
}
}
策略模式的实现大致就是这样,下面讨论下使用策略模式的好处和坏处。
好处:其一就是上面说的便于以后的变化或扩展,若以后我们要写一个吃肉的花猫的话,我们只要写一个实现IEatBehavior接口的FlowerCatEatBehavior的类就可以了,而不需要再去改动Cat类;其二,IEatBehavior接口还可以被其他对象调用,比如我们要写一Dog类,其中也有Eat()方法,那么我们可以直接调用了。当然,基于第二个好处的考虑,实现IEatBehavior接口的类的类名就得重新考虑了,总不能Dog类的Eat()委托给WhiteCatEatBehavior对象吧,虽然不影响功能的实现,But,u Know。。。怪怪的。
坏处:比较明显的就是添加了很多类,使程序看上去比较复杂,事实上确实比之前的复杂的多。但以长期角度来看,这是值得的。