设计模式之策略模式

浅谈设计模式之策略模式

       今天,小菜将更新一篇博文关于设计模式中的一个经典模式,也是一个比较简单的模式,策略模式。我们从一个例子开始,逐步深入的探讨该模式。

在现实生活中,我们都知道鸭子这种动物。鸭子会飞、会叫、会游泳。不同种类的鸭子他的外观表现也不相同,有的有一个红色的头顶,白白的身体,有的是黑色的头顶,五彩的身子。显示生活中不仅有活生生的鸭子,还有玩偶鸭子,机械鸭子,木头鸭子等等。他们当中,有的会飞、会叫、会游泳。有的只会这其中的一种或两种。假如,我们想编写一个程序,让各种鸭子一边游泳,一边呱呱叫。我先写出其中的一种方式,如上图所示。

让各种类型的鸭子继承超类Duck,然后呢,各类鸭子就自动的获得了鸣叫的quack()方法和游泳swim()方法。这个程序实现十分简单,在这里呢,就不做详细的实现了。现在出现一个新的问题,假如,我想增加一个fly()方法,这该怎么办呢?很多人的想法就是在父类Duck中直接添加fly()方法,然后所有继承该父类的子类鸭子自然获得了fly()方法。

这么做看起来非常完美,只是在父类做了一个小小的改动,就在每个子类中完美的实现了fly()方法。不过,在OtherDuck中,有的鸭子并不会飞,他们不会飞反而赋予了他们飞行的能力,这么做似乎不妥。虽然,我只是在父类Duck中做了简单的局部修改,但是所产生的影响并非是局部的。

有的人会想,既然做了继承,我就可以重写。每个初级程序员都知道我们可以重写父类的方法,用自己的实现覆盖父类中的方法。其他不会飞的鸭子,我们让他在fly()方法中什么也不做。这个想法貌似很完美的样子。也能实现我们的要求。但是,在OtherDuck中不仅有不会飞的鸭子,还有不会叫,不会游泳的鸭子。这该怎么办呢?难道说也一个一个的去覆盖么?如果一个一个的去覆盖父类的方法是不是显得有点笨拙呢。没出现一种新型的鸭子就要进行无休止的修改。

        到这里,有的基本功非常扎实的人可能想到了接口,创建FlyableQuack接口。让继承Duck的鸭子根据需要实现自己需要的接口,会叫就实现Flyable接口,会叫就实现Quack接口。问题立刻解决了,似乎很完美的样子。但是,细心地人就会发现,我们所用的代码是不可以复用的。似乎,现在没有任何好的办法来解决这个问题。在这个时候,策略模式Strategy该闪亮登场了。

        我们从新分析鸭子的问题,根据需求,似乎不同的鸭子只有flyquack的区分。我们可不可以把这两个始终可能变化的部分抽象出来呢?首先,我们先引出一个设计原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。针对我们目前的问题而言,我们就要把flyquack分别封装起来,让其他的部分不受到影响。上面这几句简单的话似乎是每个设计模式背后的精神所在哦(这句话是从大神的书上抄袭的)。就是说,让系统中的某一处改变不会影响到其他任何一处的改变。似乎这个就是设计模式的真谛。

好滴,接下来小菜就要来设计一下这个问题了。首先要把flyquack分别封装起来成为接口,分别对应FlyBehaviorQuackBehavior。对于Flyable接口,可以分出几种具体的实现,会飞,FlyWithWings(用翅膀飞)FlyWithOthers(用其他方式飞),FlyNoWay(肯定不会飞).对于Quack接口,可以分出几种具体的实现,Quack(呱呱的叫),Squack(吱吱的叫),MuteQuack(肯定不会叫)。在这里有人会问,这么做有什么好处。这里的好处是非常明显的,对于flyquack而言,如果出现了新的鸭子种类,只要实现新的种类的flyquack实现就可以了。

现在整合鸭子的行为,具体做法不多说废话,上代码。

public abstract class Duck {

 

FlyBehavior flyBehavior;

QuackBehavior quackBehavior;

 

public Duck(){

}

public void swim() {

System.out.println("I can swim");

}

 

public abstract void dispaly();

 

public void performFly() {

flyBehavior.fly();

}

 

public void performQuack() {

quackBehavior.quack();

}

}

 

public interface FlyBehavior {

public void fly();

}

 

 

 

public class FlyWithWings implements FlyBehavior{

 

public void fly() {

      System.out.println("我是用翅膀飞行的");

}

}

public class FlyWithOther implements FlyBehavior{

 

public void fly() {

     System.out.println("用其他方式飞行");

}

}

public class FlyNoWay implements FlyBehavior{

 

public void fly() {

      System.out.println("死活不会飞");

}

}

public interface QuackBehavior {

       public void quack();

}

public class Quack implements QuackBehavior{

 

public void quack() {

      System.out.println("呱呱的叫!");

}

}

public class Squack implements QuackBehavior{

 

public void quack() {

      System.out.println("吱吱的叫!");

}

 

}

public class MuteQuack implements QuackBehavior{

 

public void quack() {

      System.out.println("死活不会叫!");

}

}

 

 

 

 

public class ReadHeadDuck extends Duck{

    

public ReadHeadDuck(){

flyBehavior = new FlyWithWings();

quackBehavior = new Quack();

}

 

@Override

public void dispaly() {

      System.out.println("我是红额头的鸭子");

}

}

public class RedHeadDuckTest {

 

public static void main(String[] args) {

      Duck redHeadDuck = new ReadHeadDuck();

      redHeadDuck.performFly();

      redHeadDuck.performQuack();

      redHeadDuck.dispaly();

}

}

       哈哈哈哈,是不是非常简单,看到这里,我相信任何有一点点Java基础的已经学会了策略模式,我们上面用到了面向对象的又一个特性,多态,我们会发现,其实设计模式中用到的很多东西都是我们最基础的东西,比如说,继承,封装,多态。我们上面的代码运用了构造方法,对于构造方法,大家都知道,构造方法在当前类被实例化的时候就执行了。这样似乎不是很完美的样子,似乎太死板了点。我们接下来对代码做一下小小的修改,我们不再父类中使用构造方法,可以在测试类中随时改变鸭子的类型,从而出现不同的表现,废话不说上代码。其他类没有任何变化.

public abstract class Duck {

 

FlyBehavior flyBehavior;

QuackBehavior quackBehavior;

 

public void swim() {

System.out.println("I can swim");

}

 

public abstract void dispaly();

 

public void performFly() {

flyBehavior.fly();

}

 

public void performQuack() {

quackBehavior.quack();

}

 

public void setFlyBehavior(FlyBehavior fb) {

flyBehavior = fb;

}

 

public void setQuackBehavior(QuackBehavior qb) {

quackBehavior = qb;

}

}

public class RedHeadDuckTest {

 

/**

 * @param args

 */

public static void main(String[] args) {

      Duck redHeadDuck = new ReadHeadDuck();

      redHeadDuck.performFly();

      redHeadDuck.performQuack();

      redHeadDuck.setFlyBehavior(new FlyNoWay());

      redHeadDuck.performFly();

      redHeadDuck.dispaly();

}

}

      看到了这里,设计模式之策略模式已经搞定,而且,我相信你也已经学会了策略模式。接下来总结一下我们用到的设计原则:

1. 针对接口编程,而不是真对实现编程;

2. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起;

3. 多用组合,少用耦合。

       学完了这个策略模式,我的体会是:设计模式就是使系统局部的改变而不会影响到系统的其他部分。知道了OO基础:抽象,封装,继承,多态并不足以使我设计出良好的OO系统。良好的OO设计必须具备可维护,可复用,可扩充三个特性!我们学完了某种设计模式,但是,可能很多时候都用不到,不过不用着急,把你学的东西记在心里,然后自己经常反复的练习,努力在自己的程序中使用你学到的设计模式。学习设计模式是为了生搬硬套设计模式,而是为了写出可维护,可扩展,可复用的代码。小菜现炒现卖,不喜勿喷!其中很多个人观点,跪求斧正!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值