设计模式---策略模式

来源:互联网 发布:2012法治网络知识竞赛 编辑:程序博客网 时间:2024/06/05 05:18

前言:关于设计模式

在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复现)的各种问题,所提出的解决方案。这个术语是由埃里希·伽玛(Erich Gamma)等人在1990年代从建筑设计领域引入到计算机科学的。
设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案。面向对象设计模式通常以类别或对象来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类别或对象。设计模式能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免会引起麻烦的紧耦合,以增强软件设计面对并适应变化的能力。

以上是维基百科关于设计模式的定义。

很长的一段时间里,我写代码都只会蛮干,对自己的要求也仅仅是实现功能。后来慢慢的,看到别人写的代码层次分明、逻辑清晰才发现自己弱爆了,也就开始试着抽层,有时候还觉得不赖。BUT,最近开始看设计模式了,哎,都是泪。。。

设计模式是前人开发经验总结出来的精华,是遇到某些问题时需要掌握的思维模式。是站在一个比较高的高度去审视、设计代码的逻辑、结构,让代码不光是写起来思路更清晰,日后的可扩展性和可维护性也会更好。

定义

策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立与使用算法的客户。

定义通常就是这样,看起来很拗口也不容易看懂,当你理解了,又发现确实没毛病,真的就是这个样子。。。

理解

有一系列看起来很相似的类,比如红头鸭(RedHeadDuck)、绿头鸭(MallardDuck)、橡皮鸭(RubberDuck)。很明显他们能抽出一个基类Duck,但是呢,这几个对象的某些方法的实现又会完全不一样,比如fly()、Quack()。

通常的做法是这样:

abstract class Duck {    public abstract void swim();    public abstract void fly();    public abstract void quack();}public class RedHeadDuck extends Duck{    @Override    public void swim() {        Log.e("ZXK","i can swim");    }    @Override    public void fly() {        Log.e("ZXK","i can fly");    }    @Override    public void quack() {        Log.e("ZXK","red red red");    }}public class MallardDuck extends Duck {    @Override    public void swim() {        Log.e("ZXK","i can swim");    }    @Override    public void fly() {        Log.e("ZXK","i can fly");    }    @Override    public void quack() {        Log.e("ZXK","green green green");    }}public class RubberDuck extends Duck {    @Override    public void swim() {        Log.e("ZXK","i can swim");    }    @Override    public void fly() {        Log.e("ZXK","i can't fly");    }    @Override    public void quack() {        Log.e("ZXK","rubber rubber rubber");    }}

首先,功能肯定是可以实现的,但是不够优雅,你会发现每次有新的鸭子类需要实现,都需要把所有的方法都重写一遍,共性的也会跟着倒霉,比如本例中的swim()方法。

如何改进呢?肯定有人很自然的就想到了抽象,将 fly 和 quack 抽象成接口,让各个类自己去实现好了。
但是如果这种类有很多呢?你每次实现起来依旧需要重写fly() 和 quack()方法。

这就需要用到策略模式了,策略模式的做法是:
1. 将需要变化的那一部分,比如 fly 、quack ,与不变的隔离开来:建立两组类,一组是”fly”相关 ,比如 “能飞”类和”不能飞”类;另一组是”quack”相关类,比如”叫声大”类,”叫声小”类,”不能叫”类。
2. 然后将 这两组类又抽象成接口:FlyBehavior,QuackBehavior,并实现他们。
3. 将接口作为Duck这个基类的属性。
4. 在Duck类的子类的构造函数中,通过多态,动态的改变flyBehavior和quackBehavior属性的实现类。以实现不同的效果。

代码

两个接口及其实现类:

public interface FlyBehavior {    void fly();}public interface QuackBehavior {    void quack();}public class FlyNoWings implements FlyBehavior {    @Override    public void fly() {        Log.e("ZXK","i can't fly");    }}public class FlyWithWings implements FlyBehavior {    @Override    public void fly() {        Log.e("ZXK","i can fly");    }}public class RedQuack implements QuackBehavior {    @Override    public void quack() {        Log.e("ZXK","red red red");    }}public class GreenQuack implements QuackBehavior {    @Override    public void quack() {        Log.e("ZXK","green green green");    }}public class RubberQuack implements QuackBehavior {    @Override    public void quack() {        Log.e("ZXK","rubber rubber rubber");    }}

Duck及其子类:

public abstract class Duck {    FlyBehavior flyBehavior;    QuackBehavior quackBehavior;    public void swim() {        Log.e("ZXK", "i can swim");    }    public void performFly() {        flyBehavior.fly();    }    public void performSwim() {        quackBehavior.quack();    }}public class RedHeadDuck extends Duck{    public RedHeadDuck() {        flyBehavior = new FlyWithWings();        quackBehavior = new RedQuack();    }}public class MallardDuck extends Duck {    public MallardDuck() {        flyBehavior = new FlyWithWings();        quackBehavior = new GreenQuack();    }}public class RubberDuck extends Duck {    public RubberDuck() {        flyBehavior = new FlyNoWings();        quackBehavior = new RubberQuack();    }}

UML图

看不清图的,右键“在新标签页中打开图片”
这里写图片描述

总结

  1. 策略模式主要用在:一系列相似对象的某些方法实现不相同。
  2. 策略模式用法:首先分析这些相似对象,构建基类。将变化的那部分方法分离出来,抽象成接口,不同的方法实现作为实现类来实现这些接口。然后将接口作为基类的属性。在构建新的子类的时候,利用多态,动态的改变接口的实现,以达到相应的实现效果。
  3. 多用组合,少用继承:利用继承去设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同得行为。然而,如果能利用组合去扩展对象的行为,就可以在运行时动态的进行扩展。添加新功能的时候无需修改旧代码,也就避免了新bug产生,更利于功能扩展。
  4. 分开变化和不会变化的部分:分别封装,互不干扰,利于后期维护和功能扩展。
  5. 针对接口编程,而不是针对实现:「针对接口编程」真正的意思是「针对超类型(supertype)编程」,可以是接口也可以是超类。关键在于利用多态,动态改变实现。
原创粉丝点击