Head First 设计模式--1策略模式 组合优于继承

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

首先看个错误的面向对象。

假如我们需要写一个关于鸭子的程序,各种类型的鸭子。第一想到的就是建一个Duck接口,然后各种鸭子实现这个接口。

interface Duck{
  public void quack();
}

class MiniDuck implements Duck{
  @Override
  public void quack() {
    //........
  }
}

但是如果突然有一天,有个新需求,要有一个会飞的鸭子。那么炸了,在Duck上添加一个fly方法,所有的实现类都需要重写这个方法,如果真的有这个耐心把所有的类上都添加了一个新的方法,但是之前的测试你还需要重新一个一个的测试。确定要这么干。这时也许会想到另外一个方法,不在Duck上添加,只需要在会飞的那类鸭子中添加一个方法。如果你这么想,当初设计这个Duck接口干什么。直接写每个类啊,如果真的就这么干了,假如某个某个方法中,传入的参数只需要一个鸭子,不管什么类型的鸭子。要怎么处理。。。

经过上面这么一想,Duck是一定要有的,这时的想法会是在创建两个接口,一个Flyable接口,一个Quackable接口,这两个接口分别有fly和quack方法,Duck中有自己的方法。如果这么弄,那么每个鸭子首先要实现Duck接口,其次,根据具体功能在判断需不需要集成另外两个接口。你感觉这样真的好?如果感觉还可以接受,突然有一天,大多数的鸭子又有了一个查看颜色的方法。你需要在写第三个接口来让实现类鸭子实现。40个类同时实现这个接口,想一想工作量。

设计原则:找到应用中可能要变化之处,把他们独立出来,不要和那些不变的代码混在一起。

这里我们知道鸭子的飞和叫是变化的,就把这两部分抽出来,让他们远离鸭子类。设计两组类处理飞和叫。

设计原则:针对接口编程而不是针对实现编程。(这里所说的针对接口编程指的是针对超类,关键在于利用多态,接口并不一定是interface,可以在没有interface的情况下“针对接口编程”,只是一般来说我们用interface和abstract来当超类)

我们利用接口来代表每个行为,创建一个FlyBehavior和一个QuackBehavior,行为的每个实现都将实现上面的接口,而不是由Duck类来实现上面的接口。原来的时候,行为由Duck超类来实现或由子类具体实现。这两种做法都是依赖于实现。而现在的实现是在每个接口的子类,不会绑定在Duck身上。

直接看代码

interface FlyBehavior {
  public void fly();
}

class FlyWithWings implements FlyBehavior {
  @Override
  public void fly() {
    System.out.println("i am flying");
  }
}

class FlyNoWay implements FlyBehavior {
  @Override
  public void fly() {
    System.out.println("i can not fly");
  }
}


interface QuackBehabior {
  public void quack();
}

class Quack implements QuackBehabior {
  @Override
  public void quack() {
    System.out.println("Quack");
  }
}

class MuteQuack implements QuackBehabior {
  @Override
  public void quack() {
    System.out.println("<< Silence >>");
  }
}

class Squeak implements QuackBehabior {
  @Override
  public void quack() {
    System.out.println("Squeak");
  }
}


abstract class Duck {
  FlyBehavior flyBehavior;
  QuackBehabior quackBehabior;

  public void setFlyBehabior(FlyBehavior fb) {
    this.flyBehavior = fb;
  }

  public void setQuackBehavior(QuackBehabior qb) {
    this.quackBehabior = qb;
  }

  public Duck() {}

  public abstract void display();

  public void performFly() {
    flyBehavior.fly();
  }

  public void performQuack() {
    quackBehabior.quack();
  }

  public void swim() {
    System.out.println("all ducks float");
  }
}

class MallardDuck extends Duck {
  public MallardDuck() {
    quackBehabior = new Quack();
    flyBehavior = new FlyWithWings();
  }

  @Override
  public void display() {
    System.out.println("i am a Mallard duck");
  }
}

类图:

这里Duck是不是应该也设计成接口?这个要根据自己具体的程序来定,在这个程序中,并不需要,让Duck成为一个具体类可以让继承的子类与Duck具有相同的属性和方法,比如swim方法,不用每个继承类在去重写swim方法,游泳都是一样的游泳。

这里的设计模式就是用到的策略模式,如果想动态的设置鸭子的飞行方式,在运行时,只要设置一个对应的FlyBehavior即可。

设计原则:多用组合,少用继承

原文地址:https://www.cnblogs.com/badboyf/p/6184245.html