设计模式(Design pattern),刚开始进行了解,听说这是跻身编程上流社会的途径之一哈哈哈。不过无论如何,虽然刚刚入门,却被其能将优雅与实用两者所结合的能力所吸引。
刚刚学习的设计模式之一 —— 策略模式,顺便将其整理并且记录下来,方便加强记忆。
比如我们现在需要实现三种鸭子(duck):绿头鸭(mallardDuck)、红头鸭(redheadDuck)和小孩子洗澡玩的橡皮鸭子(rubberDuck)。这些鸭子都有一样的行为,比如都会叫(quack)、游泳(swim),以及他们都有各自的外表(display)。
那么通常的做法我们会定义一个 Duck 父类,分别实现三个方法:quack()、swim()和display()。
然后再创建三个子类分别是 MallardDuck、RedheadDuck 和 RubberDuck。三个子类继承父类Duck ,由于三种鸭子叫声以及游泳的行为是一致的,而只有外表不一样,所以只需要改写父类的 swim() 方法即可实现。
public class Duck {
public void quack() {
}
public void swim() {
}
public void display() {}
}
public class MallardDuck extends Duck {
public void display() {
}
}
public class RedheadDuck extends Duck {
public void display() {
}
}
public class RubberDuck extends Duck {
public void display() {
}
}
那么如果对于活的鸭子需要增加 飞(fly)这个行为,应该如何处理呢?可以在 Duck 类增加 fly() 方法来实现该行为。但是如此做的话,这个不会飞的橡皮鸭则也随着具有 飞 这个行为了。
为了解决新的问题,我们可以在RubberDuck 类中重写 fly 方法。
public class RubberDuck extends Duck {
public void display() {
}
public void fly() {
// 什么也不做
}
}
但是如此做又会有新的问题出现,既是如果往后还需要实现木鸭子、铁鸭子这些不会飞的鸭子的话,我们都需要改写 fly() 行为方法。而如果存在差异的行为越多,则需要在更多的类中去改写更多方法,存在的问题也就越大,这么做不优雅。
那么有没有其他方法呢,是否可以将 fly 行为单独写成一个接口呢,然后需要具备 fly 行为的鸭子则去实现改接口。
public interface FlyBehavior {
public abstract void fly();
}
public class MallardDuck extends Duck implements FlyBehavior{
public void display() {
}
@Override
public void fly() {
}
}
然而这样子处理的话,则需要在每一个会飞的鸭子类中都实现该接口。如此做也会随着类与差异行为的增多的变得繁琐。
如何解决这个问题呢?这里有一个设计原则:
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
意思则是,既然除了 fly 这个行为,其他行为似乎不需要做多大的修改的话,那么就把 fly 这个行为独立出来,我们可以拿一个类实现 飞(FlyWithWings),一个类实现 不会飞(FlyNoWay)。
那么如何设计这两个类呢,这里还有一个设计原则:
针对接口编程,而不是针对实现编程。
根据上面的原则,我们可以创建一个 FlyBehavior 接口,然后分别使用FlyWithWings 和FlyNoWay 实现该接口。而不是直接创建两个类。这样做的好处是,利用多态,程序可以针对超类型编程。
// 针对实现编程
FlyWithWings flyWithWings = newFlyWithWings();
flyWithWings.fly();
// 针对实现编程
FlyBehavior flyBehavior = newFlyWithWings();
flyBehavior.fly();
那么接下来就可以来解决鸭子 飞 的行为了。首先,我们创建FlyBehavior 接口以及实现FlyWithWings 和FlyNoWay 两个类。
public interface FlyBehavior {
public void fly();
}
public class FlyWithWinds implements FlyBehavior {
@Override
public void fly() {
}
}
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
}
}
然后在 Duck 父类中加入飞这个行为:
public abstract class Duck {
FlyBehavior flyBehavior;
public Duck() {}
public abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void quack() {
}
public void swim() {
}
}
现在来实现会飞的绿头鸭:
public class MallarDuck extends Duck {
public MallarDuck() {
flyBehavior = new FlyWithWinds();
}
@Override
public void display() {
}
}
最后输入测试类:
public class MiniDuckSimulator {
public static void main(String[] args) {
Duck mallard = new MallarDuck();
mallard.display();
mallard.performFly();
}
}
运行则可以看到相关的结果:
这样子即使多个类以及多个差异行为,也可以非常灵活的实现每一个差异行为。而如果需要更加灵活,还可以动态的设定行为。
首先,在 Duck 类中加入新方法:
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
然后为了让鸭子有特异功能,新建一个火箭飞行行为,由于是 飞 这个行为的一种,则依旧实现 FlyBehavior 接口:
public class FlyRocketPowered implements FlyBehavior {
@Override
public void fly() {
}
}
最后通过动态的修改绿头鸭的飞行行为:
public class MiniDuckSimulator {
public static void main(String[] args) {
Duck mallard = new MallarDuck();
mallard.performFly();
mallard.setFlyBehavior(new FlyRocketPowered());
mallard.performFly();
}
}
运行则可以看到相关的结果:
这样子,我们将多个类组合起来,而不是通过继承的方式来实现不同类间存在差异行为的问题,这样使得行为更加的灵活。这也顺承了第三个设计原则:
多用组合,少用继承。
而上面这个设计模式,也就是策略模式。
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的百年法独立于使用算法的客户。
领取专属 10元无门槛券
私享最新 技术干货