以前看过Head First设计模式这本书,时间长了温习下,顺便写下博客总结下:
我们先来看下这个例子:uml图如下,做了一个鸭子的游戏。有各种鸭子,可以游泳,叫,还有各种显示。因此做了一个Duck的父类,子类只有display不一样。
现在,需要定义一些会飞的鸭子,但是也有比如玩具鸭不会飞。那我们应该怎么实现呢?有几种方法
1. 如果我们在Duck中添加fly方法,那么所有的子类都会飞了。如果那个特定的子类不会飞,就需要那个子类实现fly这个方法,并且空实现。但是这样非常麻烦,而且我后面又要增加别的功能,比如不会叫的鸭,就要在子类中把quack这个方法给空实现了,才行。所以这不是种好方法。而且代码在多个子类中重复
2. 还有一种方法我们定义两个interface 一个 Flyable 一个Quackable。然后在各个子类中自己实现。但是这样的话,重复代码会非常多。
3. 因此最好的方法是我们自己定义两个行为类,一个FlyBehavior 一个QuackBehavior 这两个类是Interface。然后在Duck中定义两个该Interface的对象,并且可以定义接口,动态添加行为。
public abstract class Duck {
FlyBehavior flyBehavior;//在父类中定义了两个行为类
QuackBehavior quackBehavior;
public Duck() {}
public abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();//委托行为类
}
public void swim() {
System.out.println("All ducks swim")
}
}
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();//针对接口编程,这里接口就是统一的父类或者Interface
flyBehavior = new FlyWithWings();
}
public void display() {
System.out.println("I'm real Mallard Duck.");
}
}
public interface FlyBehavior {//接口
public void fly();
}
public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("I'm flying");
}
}
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("I can't fly");
}
}
public interface QuackBehavior {
public void quack();
}
public class QuackBehavior implements QuackBehavior {
public void quack() {
System.out.println("quack");
}
}
public class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("slience")
}
}
测试类
public class MiniDuckSimulator {
public static main(String[] args) {
Duck mallard = new MallardDuck();
mallard.performFly();
mallard.performQuack();
}
}
这里有几个设计原则:
1. 找出应用中可能需要变化之处,把它独立出来,不要和那些不需要变化的代码混在一起。
2. 针对接口编程,而不是针对实现编程。
3. 多用组合,少用继承。
当然最后我们可以在Duck类中加入两个新的方法,就可以动态改变鸭子的行为:
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb) {
quackBehavior = qb;
}
我们可以键一个新的FlyBehavior类型
public class FlyRockedPowered implements FlyBehavior {
public void fly() {
System.out.println("I'm flying with a rocket!");
}
}
这样我们就可以改变下测试类:
测试类
public class MiniDuckSimulator {
public static main(String[] args) {
Duck mallard = new MallardDuck();
mallard.performQuack();
mallard.performFly();
mallard.setFlyBehavior(new FlyRockedPowered());
mallard.performFly();
}
}
结果:
quack
I'm flying
I'm flying with a rocket!
最后我们再来看看uml图:
这种模式就是策略模式:
定义了算法族,分别封装起来(这里就是我们的行为类),让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。