策略模式
什么是策略模式?
策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
策略模式涉及的OO涉及原则
- 将代码中变化的部分与不变化的部分分离并封装,以达到复用的效果
- 面向接口编程,而不是面向实现编程
- 使用组合,而不是用继承
策略模式案例
现有一个关于鸭子的系统,原有系统的设计如下:
现有一个需求,鸭子可以在屏幕上乱飞。看到这个需求,我的本能反应:Are you kidding me?!这么简单,哈哈,直接在父类Duck中添加fly()方法不就行了,so easy。所以系统的设计修改如下:
好烦,项目经理又改需求了,公司的业务拓展了,现在也卖:玩具鸭子…,好吧,又要改设计了,不过这也难不倒我,直接创建一个继承于Duck类的玩具鸭子就好了呀。唉,我一直在承受我这个年纪不该有的机智和帅气,我好累!!! ^V^。so,设计又变成了下面这个样子:
代码改完的第二天,项目经理走到我的办公桌前,”小李,你来一下我办公室。”“哈哈,难道我帅气的外表已经掩盖不住我盖世的才华了吗!嘻嘻,要加薪了,马上就要走上人生巅峰,赢取白富美了。哇,早就知道这天不会太远,但是好突然,还没准备好,肿么办。嗯,就这么决定了,明天就娶个白富美,哈哈^V^…”。”小李,什么情况,公司系统的玩具鸭子也会飞,是什么情况,侬脑子坏特啦!!!”。没错,重要的事情说三遍:侬脑子歪特啦!!!,侬脑子歪特啦!!!,侬脑子歪特啦!!!。腹诽:”侬脑子歪特啦!!! 侬全家脑子都歪特啦”。额,圈错了重点……重点好像是:玩具鸭子会飞。握草,玩具鸭子会飞,玩具鸭子会飞,玩具鸭子会飞,肿么办?! Fuck,又要该设计! 我想唱首歌,想问天问大地,我做错了什么。Ok,自己作的孽,自己来承担后果,改吧…灵机一动,ToyDuck覆盖Duck中的fly()方法,且fly()方法没有具体实现即可。所以,设计图成了这样:
但是这样设计好像有点问题?具体是什么问题呢?如果说,还有其他类别不会飞的鸭子,难道每次创建新类,都要重写fly()方法,最重要的是,重写的fly()方法没有任何实现,好傻的设计…好吧,重点不是fly()方法没有任何实现,而是:每新创建一个类,都要覆盖方法,ToyDuck中的fly方法,没有复用…淡淡的忧桑。谁能告诉我,该怎么设计,who can tell me?
看到了这里,相信大家都已经有思路了。今天总结的是:策略模式。so,答案就是:策略模式。注意:每个女人(设计模式)的背后都有几个男人(OO设计原则)默默的支持。是哪些男人(OO涉设计模式)呢?
- 将代码中变化的部分与不变化的部分分离并封装,以达到复用的效果
- 面向接口编程,而不是面向实现编程
- 使用组合,而不是用继承
套一套这三点OO设计原则,设计可以改变如下:
这个案例中有哪些是可变的?
- 叫声:真实的鸭子的叫声是:嘎嘎;玩具鸭子是:吱吱;其他的鸭子可能是其他的叫声
- 飞:真实的鸭子会飞;玩具鸭不会飞
如果这两个行为都在Duck类中,已经写好实现,那真是一个糟糕的设计。
第一个OO原则:将变化的与不变化的分离并封装。
分离出来,那么封装成什么,类么?很明显,抽象成类不合适,叫与飞只是一个行为。
然后又根据第二个OO原则:面向接口编程。
自然而然,这两个行为可以分离,封装成接口:Quack、Flyable。
设计如下:
那么设计现在已经被改的面目全非。但是这样的设计,扩展性很好。
最后设计的代码(Java)如下:
public abstract class Duck {
String name;
Quack quack;
Flyable flyable;
public abstract void display();
public void performQuack(){
quack.quack();
}
public void performFly() {
flyable.fly();
}
}
public class DomesticDuck extend Duck {
public DomestisDuck(Quack quack, Flyable flyable) {
this.quack = quack;
this.flyable = flyable;
}
public void display(){
//方法体
}
}
public class WildDuck extend Duck {
public WildDuck(Quack quack, Flyable flyable) {
this.quack = quack;
this.flyable = flyable;
}
public void display(){
//方法体
}
}
public class ToyDuck extend Duck {
public ToyDuck(Quack quack, Flyable flyable) {
this.quack = quack;
this.flyable = flyable;
}
public void display(){
//方法体
}
}
public interface Quack {
void quack();
}
//嘎嘎叫
public class GaGaQuack implements Quack{
public void quack() {
System.out.println("gaga...");
}
}
//吱吱叫
public class ZhiZhiQuack implements Quack {
public void quack() {
System.out.println("zhizhi...");
}
}
public interface Flyable {
void flyable();
}
//会飞
public class CanFly implements Flyable{
public void flyable() {
System.out.println("can fly...");
}
}
//不会飞
public class CanNotFly implements Flyable{
public void flyable() {
System.out.println("can not fly...");
}
}
public class Test {
public static void main(String[] args) {
DomesticDuck duck1 = new DomesticDuck(new GaGaQuack(), new CanFly());
WildDuck duck2 = new WildDuck(new GaGaQuack(), new CanFly());
ToyDuck duck3 = new ToyDuck(new ZhiZhiQuack(), new CanNotFly());
duck1.performQuack();
duck1.performFly();
duck2.performQuack();
duck2.performFly();
duck3.performQuack();
duck3.performFly();
}
}