本文经过简单的模拟鸭子应用作起,在模拟鸭子游戏中,会出现各类鸭子,鸭子能够游泳、能够呱呱叫。java
如今客户想让鸭子能够飞行,因而赞成了这个需求,类图变成了下面这样算法
这是,可怕的问题发生了,有许多“橡皮鸭子”能够在游戏界面飞来飞去,这是在设计上的疏忽,由于在超类上加上fly(),就会致使全部的子类都具有fly(),连那些不应具有fly()的子类也没法免除。设计模式
我能够把fly()从超类中取出来,放进一个“Flyable接口”中。这么一来,只有会飞的鸭子才实现此接口。一样的方式,也能够用来设计一个“Quackable接口”,由于不是全部的鸭子都会叫。 测试
咱们知道,并不是“全部”的子类都具备飞行和呱呱叫的行为,因此继承并非适当的解决方式。虽然Flyable与Quackable能够解决“一部分”问题(不会再有会飞的橡皮鸭),可是却形成代码没法复用,这只能算是从一个恶梦跳进另外一个恶梦 。spa
这个时候咱们想到一个设计原则插件
找出应用中可能须要变化之处,把它们独立出来,不要和那些不须要变化的代码混在一块儿。
咱们知道Duck类内的fly()和quack()会随着鸭子的不一样而改变。 设计
下面开始设计鸭子的行为3d
首先,在Duck类中“加入两个实例变量” ,分别为“flyBehavior”与“quackBehavior”,声明为接口类型(而不是具体类实现类型),每一个鸭子对象都会动态地设置这些变量以在运行时引用正确的行为类型 。code
编写Duck类orm
public abstract class Duck { //为行为接口类型声明两个引用变量,全部鸭子类都继承它们 FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck() { } abstract void display(); public void performFly() { //委托给行为类 flyBehavior.fly(); } public void performQuack() { //委托给行为类 quackBehavior.quack(); } public void swim() { System.out.println("All ducks float, even decoys!"); } }
编写MallardDuck类
public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } public void display() { System.out.println("I'm a real Mallard duck"); } }
编写ModelDuck类
public class ModelDuck extends Duck { public ModelDuck() { flyBehavior = new FlyNoWay(); quackBehavior = new Quack(); } public void display() { System.out.println("I'm a model duck"); } }
编写FlyBehavior接口与两个行为实现类
FlyBehavior接口
public interface FlyBehavior { public void fly(); }
FlyNoWay
public class FlyNoWay implements FlyBehavior { public void fly() { System.out.println("I can't fly"); } }
FlyWithWings
public class FlyWithWings implements FlyBehavior { public void fly() { System.out.println("I'm flying!!"); } }
编写QuackBehavior接口与三个实现类
public interface QuackBehavior { public void quack(); }
Quack实现类
public class Quack implements QuackBehavior { public void quack() { System.out.println("Quack"); } }
MuteQuack
public class MuteQuack implements QuackBehavior { public void quack() { System.out.println("<< Silence >>"); } }
Squack
public class Squeak implements QuackBehavior { public void quack() { System.out.println("Squeak"); } }
编写测试类
public class MiniDuckSimulator { public static void main(String[] args) { MallardDuck mallard = new MallardDuck(); mallard.display(); mallard.performQuack(); mallard.performFly(); Duck model = new ModelDuck(); model.display(); model.performQuack(); model.performFly(); } }
运行结果
Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组算法, 将每一个算法都封装起来, 而且使它们之间能够互换。 )
通用类图
策略模式使用的就是面向对象的继承和多态机制, 很是容易理解和掌握, 咱们再来看看策略模式的三个角色:
实现抽象策略中的操做, 该类含有具体的算法
若是没有策略模式, 咱们想一想看会是什么样子? 一个策略家族有5个策略算法, 一会要使用A策略, 一会要使用B策略, 怎么设计呢? 使用多重的条件语句? 多重条件语句不易维护, 并且出错的几率大大加强。 使用策略模式后, 能够由其余模块决定采用何种策略, 策略家族对外提供的访问接口就是封装类, 简化了操做, 同时避免了条件语句判断。
在现有的系统中增长一个策略太容易了, 只要实现接口就能够了, 其余都不用修改, 相似于一个可反复拆卸的插件, 这大大地符合了OCP原则。
每个策略都是一个类, 复用的可能性很小, 类数量增多。
参考书籍:《Head First 设计模式》《设计模式之禅》