开门见山,首先表明什么是策略模式
策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
好像从定义上来看,并不能明白什么是策略模式,那么让我们从一个问题上下手:
怎么设计一个鸭子类?
很简单,让我们运用面向对象的思想,万物皆对象嘛,鸭子可以叫,可以飞,可以游泳。。。把功能封装成方法不就好了,那么,写出来就是
class Duck
{
public void display(){}//外观
public void fly(){} //飞
public void swim(){} //游泳
public void quack(){}// 叫
}
问题到这里好像解决了,没有什么不对,这时候你侄女跑过来向你要一个橡皮鸭,作为一个java程序员,直接new出来就好啦,我们有刚才写出来
的鸭子类,橡皮鸭也是鸭子,于是你直接:
class RubberDuck extends Duck;
侄女拿走橡皮鸭开心的走了。。。你正在为自己的机智沾沾自喜的时候,侄女哭哭啼啼跑过来了,跟你说:
”你给我的橡皮鸭子飞了“
搞笑!橡皮鸭子怎么会飞!不过你好像突然意识到什么。。。。
对了,就在刚才,鸭子类有个fly方法!这好办,做个空实现就好了。
但是作为一个正在学习设计模式的java程序员,你隐隐感觉到不安。。。。
尽管飞,游泳,叫看起来很像一个鸭子应该具备的,但是实际情况并不是如此,橡皮鸭不会飞,木头鸭不会叫,每次继承的时候,都需要根据实际情况具体分析,做修改(比如空实现),这可不是我的风格。
这么看来,继承可能不是一个很好的解决方案,那么,接口呢?
把Duck写成接口?不不不,这样完全无济于事,我们要把鸭子类中变化的部分和不变得部分分离开来,从鸭子类来说,变化的事fly()和quack(),不变得是display()和swim()(这样我们就让鸭子的行为独立于鸭子,已经摸到策略模式的门槛了),所以我们可以这样做:
构造两个接口Flyable和Quackable,让橡皮鸭只实现Quackable,写起来就像这样
class RuberDuck extends Duck implements Quackable (此时Duck类只含有display()和swim()这两个固定方法)
这样既解决了橡皮鸭会飞的问题又保证了橡皮鸭身上没有什么奇奇怪怪的按钮(比如I can fly,指的是fly的空实现)
但是,你觉得事情好像没这么简单,要是有很多种鸭子呢?10,20,30.。。或者更多,你需要每种鸭子都实现接口,要命的是,接口里并没有具体实现的代码,要知道,很多种类的鸭子的fly()和quack()都是相同的,
也就意味着你需要写很多很多相同的代码,这可不是一个程序员想做的事。
换句话说,要解决的问题就是增加代码的复用性。
怎么办呢?让我们想想。。。。组合或许是解决问题的方法。。。运用组合的话,Duck类应该是这样:
class Duck
{
Quackable quackable;
Flyable flyable;
public void display(){}//外观
public void fly(){
flyable.fly();
} //飞
public void swim(){} //游泳
public void quack(){
quackable.quack();
}// 叫
}
上述代码体现了一个很重要的原则:面对接口/超类编程,可以看出,我们在Duck类中组合的是两个接口而不是具体子类,这样可以让我们尽可能少的去修改代码。
我们来实现一下RuberDuck!
class RuberDuck extends Duck
{
public RuberDuck()
{
quackable=new RuberQuack();//实现了橡皮鸭呱呱叫
Flyable =new RuberFly();//实现了不能飞
}
public void display(){}//外观
public void fly(){
flyable.fly();
} //飞
public void swim(){} //游泳
public void quack(){
quackable.quack();
}// 叫
}
对比一下,实现RuberDuck的过程中,我们做了两件事:继承接口实现RuberDuck的fly()和quack()和在RuberDuck的构造方法中对quackable和flyable进行初始化,
一切进行的很完美,但是我们不能满足于此,我们要能满足奇怪的需求,比如,让一只橡皮鸭突然飞一下来吓小侄女一跳,也就是说,要动态的控制行为而不是在
编译过程中就将行为确定 。那我们可以这样:
class Duck
{
public void display(){}//外观
public void fly(Flyable flyable){
flyable.fly();
} //飞
public void swim(){} //游泳
public void quack(Quackable quackable){
quackable.quack();
}// 叫
}
就可以实现鸭子行为的动态改变。
好了,到这里我们运用策略模式完成了对Duck类的“改装”,在这个过程中,我们先将Duck类中变与不变的部分分离开来,把变化的部分封装成了算法族,利用组合
和接口让算法之间可以相互替换。
博主注:这篇文章是博主的第一篇博文,所以在很大程度上借鉴了head frist 中的行文模式,还望head frist 系列丛书的作者以及书迷们海涵,博文中如有错误,
还希望读者给予指正。
策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
好像从定义上来看,并不能明白什么是策略模式,那么让我们从一个问题上下手:
怎么设计一个鸭子类?
很简单,让我们运用面向对象的思想,万物皆对象嘛,鸭子可以叫,可以飞,可以游泳。。。把功能封装成方法不就好了,那么,写出来就是
class Duck
{
public void display(){}//外观
public void fly(){} //飞
public void swim(){} //游泳
public void quack(){}// 叫
}
问题到这里好像解决了,没有什么不对,这时候你侄女跑过来向你要一个橡皮鸭,作为一个java程序员,直接new出来就好啦,我们有刚才写出来
的鸭子类,橡皮鸭也是鸭子,于是你直接:
class RubberDuck extends Duck;
侄女拿走橡皮鸭开心的走了。。。你正在为自己的机智沾沾自喜的时候,侄女哭哭啼啼跑过来了,跟你说:
”你给我的橡皮鸭子飞了“
搞笑!橡皮鸭子怎么会飞!不过你好像突然意识到什么。。。。
对了,就在刚才,鸭子类有个fly方法!这好办,做个空实现就好了。
但是作为一个正在学习设计模式的java程序员,你隐隐感觉到不安。。。。
尽管飞,游泳,叫看起来很像一个鸭子应该具备的,但是实际情况并不是如此,橡皮鸭不会飞,木头鸭不会叫,每次继承的时候,都需要根据实际情况具体分析,做修改(比如空实现),这可不是我的风格。
这么看来,继承可能不是一个很好的解决方案,那么,接口呢?
把Duck写成接口?不不不,这样完全无济于事,我们要把鸭子类中变化的部分和不变得部分分离开来,从鸭子类来说,变化的事fly()和quack(),不变得是display()和swim()(这样我们就让鸭子的行为独立于鸭子,已经摸到策略模式的门槛了),所以我们可以这样做:
构造两个接口Flyable和Quackable,让橡皮鸭只实现Quackable,写起来就像这样
class RuberDuck extends Duck implements Quackable (此时Duck类只含有display()和swim()这两个固定方法)
这样既解决了橡皮鸭会飞的问题又保证了橡皮鸭身上没有什么奇奇怪怪的按钮(比如I can fly,指的是fly的空实现)
但是,你觉得事情好像没这么简单,要是有很多种鸭子呢?10,20,30.。。或者更多,你需要每种鸭子都实现接口,要命的是,接口里并没有具体实现的代码,要知道,很多种类的鸭子的fly()和quack()都是相同的,
也就意味着你需要写很多很多相同的代码,这可不是一个程序员想做的事。
换句话说,要解决的问题就是增加代码的复用性。
怎么办呢?让我们想想。。。。组合或许是解决问题的方法。。。运用组合的话,Duck类应该是这样:
class Duck
{
Quackable quackable;
Flyable flyable;
public void display(){}//外观
public void fly(){
flyable.fly();
} //飞
public void swim(){} //游泳
public void quack(){
quackable.quack();
}// 叫
}
上述代码体现了一个很重要的原则:面对接口/超类编程,可以看出,我们在Duck类中组合的是两个接口而不是具体子类,这样可以让我们尽可能少的去修改代码。
我们来实现一下RuberDuck!
class RuberDuck extends Duck
{
public RuberDuck()
{
quackable=new RuberQuack();//实现了橡皮鸭呱呱叫
Flyable =new RuberFly();//实现了不能飞
}
public void display(){}//外观
public void fly(){
flyable.fly();
} //飞
public void swim(){} //游泳
public void quack(){
quackable.quack();
}// 叫
}
对比一下,实现RuberDuck的过程中,我们做了两件事:继承接口实现RuberDuck的fly()和quack()和在RuberDuck的构造方法中对quackable和flyable进行初始化,
一切进行的很完美,但是我们不能满足于此,我们要能满足奇怪的需求,比如,让一只橡皮鸭突然飞一下来吓小侄女一跳,也就是说,要动态的控制行为而不是在
编译过程中就将行为确定 。那我们可以这样:
class Duck
{
public void display(){}//外观
public void fly(Flyable flyable){
flyable.fly();
} //飞
public void swim(){} //游泳
public void quack(Quackable quackable){
quackable.quack();
}// 叫
}
就可以实现鸭子行为的动态改变。
好了,到这里我们运用策略模式完成了对Duck类的“改装”,在这个过程中,我们先将Duck类中变与不变的部分分离开来,把变化的部分封装成了算法族,利用组合
和接口让算法之间可以相互替换。
博主注:这篇文章是博主的第一篇博文,所以在很大程度上借鉴了head frist 中的行文模式,还望head frist 系列丛书的作者以及书迷们海涵,博文中如有错误,
还希望读者给予指正。