刚入职的公司正在开发一款游戏DuckSim,它用了最传统的面向对象来设计各种类之间的关系:
display()
是抽象的,因为不同种类的鸭子有不同的表现方式。
为了打败其它同类型游戏,产品经理提出了这个一个新的需求:“我们需要给我的的鸭子加一个fly()的功能!”
如何实现这个功能呢?最直接的方式,直接在父类Duck中添加fly()方法。
然而,在代码提交后的第二天,测试找到了我:“阿毅,你的代码有问题,直接把fly()加在Duck,但是并不是所有的鸭子都可以飞呀!
除此之外,RubberDuck的quack()方法应该与其它Duck不同,那么要如何解决这个问题呢?
第一次尝试:我们可以把quack()和fly()做成接口,对应的子类实现对应的接口即可。
然而,利用这种方法实现的话,会导致子类又大量重复的代码(如果两个种类的鸭子的fly()完全相同,它们不得不分别实现),更糟糕的是,如果有一天我们鸭子的飞行方式需要做修改,那么我们必须修改所有的类!
由此,引出两条设计规则:
1. 找出代码中相同的部分,把它们提取出来。
这样子做能够提高代码的复用性,需要添加新功能的时候,不需要修改公共的代码,减少bug发生几率。
2. 面向接口编程,而不是面向实现!。
这个由具体例子来解释。
OK,接下来回到问题,如何解决?
package designpattern.introduction;
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public void swim() {
System.out.println("I can swim");
}
public abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performSquack() {
quackBehavior.quack();
}
public static void main(String[] args) {
Duck duck = new BlackDuck();
duck.display();
duck.performFly();
duck.performSquack();
duck = new RubberDuck();
duck.display();
duck.performSquack();
duck.performFly();
}
}
interface FlyBehavior {
void fly();
}
interface QuackBehavior {
void quack();
}
class FlyWithWing implements FlyBehavior {
@Override
public void fly() {
System.out.println("I can fly with wings");
}
}
class CanNotFly implements FlyBehavior {
@Override
public void fly() {
System.out.println("I cannot fly");
}
}
class QuackNoSound implements QuackBehavior {
@Override
public void quack() {
System.out.println("NO sound!");
}
}
class Squack implements QuackBehavior {
@Override
public void quack() {
System.out.println("squack");
}
}
class Quack implements QuackBehavior {
@Override
public void quack() {
System.out.println("Quack!!!");
}
}
class BlackDuck extends Duck {
public BlackDuck() {
flyBehavior = new FlyWithWing();
quackBehavior = new Quack();
}
@Override
public void display() {
System.out.println("I'm a black duck");
}
}
class WhiteDuck extends Duck {
public WhiteDuck() {
flyBehavior = new FlyWithWing();
quackBehavior = new Quack();
}
@Override
public void display() {
System.out.println("I'm a white duck");
}
}
class RubberDuck extends Duck {
public RubberDuck() {
flyBehavior = new CanNotFly();
quackBehavior = new Squack();
}
@Override
public void display() {
System.out.println("I'm a rubber duck");
}
}