简析设计模式之策略模式
来源:互联网 发布:代理商查询系统源码 编辑:程序博客网 时间:2024/06/02 06:10
首先,我们从鸭子说起,鸭子都会叫和游泳,但不同的鸭子有不同的外观:
先写一个父类:
public abstract class Duck { public void quack(){ System.out.println("I'm duck, I can quack!"); } public void swim(){ System.out.println("I'm duck, I can swim!"); } public abstract void display();}
绿头鸭:
public class MallardDuck extends Duck { @Override public void display() { System.out.println("I'm green head duck"); }}
红头鸭:
public class RedHeadDuck extends Duck { @Override public void display() { System.out.println("I'm red head duck"); }}
但是,有了新的需求,我们想让鸭子飞:在父类写个fly()方法,所有的子类都继承该方法,但是,有的鸭子不会飞的,例如橡胶鸭子。这显然不是我们想要的。或许你会说,我们可以在子类中覆盖该方法,让它什么都不做,但是,如果有越来越多的其它类型的鸭子需要添加进来那又该如何?显然,会有越来越多重复的代码在子类中出现,而且如果父类稍微有点改动都会涉及到子类。继承,显然不是我们推崇的。
那么你会说,用接口来抽离出鸭子飞行和叫法的行为又怎样?
是的,这样是解决了一部分问题,起码不会出现会飞的假鸭子,但是,如果很多鸭子是会飞行以及叫法一样的,是不是又造成代码无法复用的问题?接口不具备实现功能,所以无法达到代码的复用。
但是,问题总是得解决的。我们只能从涉及原则中寻找答案了:
把可能变化的代码抽离并封装起来,好让其它部分不受影响。这是一个很简单的概念,也几乎是每个设计模式背后的精神所在。
好的,是时候对duck进行改造了,记住上面的原则:把可能变化的代码抽离并封装起来,这里的quack()和fly()是会随着鸭子的不同而改变的。
先把fly和quack抽离出来:
public interface FlyBehavior { void fly();}
public interface QuackBehavior { void quack();}
接下来,需要飞行或不需要飞行的都实现FlyBehavior接口,叫或不叫以及叫法不同的实现QuackBehavior 接口:
public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("I can fly"); }}
public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("I can't fly"); }}
类似地,quackBehavior同样如此实现。
如此一来,变化的部分已经和duck完全无关了,但是我们接下来要做的就是把他们联系起来,让不同的鸭子飞或不飞,叫或不叫:
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public void performQuack(){ quackBehavior.quack(); } public void performFly(){ flyBehavior.fly(); } public void swim(){ System.out.println("I'm duck, I can swim!"); } public abstract void display();}
这样,就把具体实现都留给了具体行为的实现类,现在,我们来看看子类的改造:
public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } @Override public void display() { System.out.println("I'm green head duck"); }}
最后来个测试类看看效果:
public class Main { public static void main(String[] args) { Duck greenDuck = new GreenHeadDuck(); greenDuck.disPlay(); greenDuck.performFly(); greenDuck.performQuack(); Duck redDuck = new RedHeadDuck(); redDuck.disPlay(); redDuck.performFly(); redDuck.performQuack(); }}
在此,我们需要记住一个原则:针对接口编程,而不是针对实现编程。由始至终,我们的程序都是尽量地遵循这个原则的。
为了使这个应用更加地弹性,我们还可以在Duck中添加set方法,动态地改变鸭子的行为,万一它哪天会飞了呢?
public void setFlyBehavior(FlyBehavior fb){ this.flyBehavior = fb; } public void setQuackBehavior(QuackBehavior qb){ this.quackBehavior = qb; }
Main方法里:
Duck redDuck = new RedHeadDuck(); redDuck.disPlay(); redDuck.performFly(); redDuck.performQuack(); redDuck.setFlyBehavior(new FlyWithSwings()); redDuck.performFly();
其实,这就是另外一个设计原则:少用继承,多用组合。如同本例,当你将两个以上的类结合使用,就是组合。鸭子的行为不是继承过来的,而是适当地与行为对象组合而来的。
软件开发总是要花大量的时间在维护与升级上,而好的设计模式往往能帮我们减少大量的时间的消费。多用组合,少用继承。
最后,也是时候揭晓谜底了,这就是策略模式:
所谓策略模式就是定义了算法簇,分别封装起来,让它们之间可以互相替换。此模式让算法的变化独立于使用算法的客户。
- 简析设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- 设计模式之策略模式
- pythonWeb -- Django开发- 模型Model 和 数据库的操作
- 203. Remove Linked List Elements(Java)
- 高级表单与表格、BFC研究
- 自己实现一个简单的散列表
- PoEdu_Python_Lesson010_类的特性
- 简析设计模式之策略模式
- 如何判断JVM是运行在Client模式还是Server模式?
- tf-idf关键词提取算法
- 【MySQL】(2)MySQL基础语法
- 精彩的网文汇总分享
- 2017.07.22工作日记
- Python学习04_图像数据类型及颜色空间转换
- 图像处理9:扩散填充
- 关于JVM 的GC收集器