首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Design pattern 策略模式

设计模式(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();

}

}

运行则可以看到相关的结果:

这样子,我们将多个类组合起来,而不是通过继承的方式来实现不同类间存在差异行为的问题,这样使得行为更加的灵活。这也顺承了第三个设计原则:

多用组合,少用继承。

而上面这个设计模式,也就是策略模式。

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的百年法独立于使用算法的客户。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180811G1L20300?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券