作者:Grey

原文地址:http://www.cnblogs.com/greyzeng/p/5915202.html

模式名称

策略模式(Strategy Pattern)

需求

模拟鸭子游戏,游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。我们应该如何设计这个鸭子类呢?

解决方案

首先,我们可以考虑设计一个鸭子的超类Duck,抽象出鸭子的公共方法,然后其他鸭子类型继承这个超类,对公共方法有自己独有的实现。

public abstract class Duck {

    public abstract void display();
public abstract void quack(); public void swim() {
System.out.println("all ducks can swim");
} }
public class RedHeadDuck extends Duck {

    @Override
public void display() {
System.out.println("This is RedHeadDuck");
} @Override
public void quack() {
System.out.println("RedHeadDuck Quack");
}
}
public class ModelDuck extends Duck {
@Override
public void display() {
System.out.println("This is ModelDuck");
} @Override
public void quack() {
System.out.println("ModelDuck Can not Quack");
}
}

但是,这种设计,会出现一个问题:

如果要增加一个可以飞的鸭子,我们在超类中增加一个fly()方法,所有继承这个超类的子类都会有这个方法,导致代码在多个子类中重复。

public abstract class Duck {

    public abstract void display();
public abstract void quack();
public abstract void fly(); public void swim() {
System.out.println("all ducks can swim");
} }
public class RedHeadDuck extends Duck{

    @Override
public void display() {
System.out.println("This is RedHeadDuck");
} @Override
public void quack() {
System.out.println("Gua Gua Gua~~");
} @Override
public void fly() {
System.out.println("fly fly fly~~");
}
}
public class ModelDuck extends Duck{
@Override
public void display() {
System.out.println("This is ModelDuck");
} @Override
public void quack() {
System.out.println("Silence");
} @Override
public void fly() {
// do nothing
}
}

更好的一种方法:

分开变化与不变化的部分,因为Duck类里面fly()quack()会随着鸭子的不同而改变,所以我们需要把这两个行为从Duck里面分离出来,建立一组新类来代表每个行为

QuackBehavior接口:

interface QuackBehavior {
void quack();
}

QuackBehavior 具体行为:

public class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("Silence");
}
}
public class Gua implements QuackBehavior {

    public void quack() {
System.out.println("Gua Gua Gua~~");
}
}

FlyBehavior接口:

interface FlyBehavior {
void fly();
}

FlyBehavior具体行为:

public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("fly fly fly~~~");
}
}
public class FlyNoWay implements FlyBehavior {
public void fly() {
// do nothing
}
}

现在鸭子会将飞行和呱呱叫的动作“委托”给FlyBehaviorQuackBehavior处理,我们在Duck中增加两个方performFly(),performQuack()

public abstract class Duck {
Duck() {} public FlyBehavior flyBehavior;
public QuackBehavior quackBehavior; public abstract void display(); public void swim() {
System.out.println("all ducks can swim");
}
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
}

在每种鸭子继承超类Duck的时候,只需要在构造函数中设置对应的FlyBehaviorQuackBehavior实例变量即可。

public class RedHeadDuck extends Duck {
RedHeadDuck() {
this.quackBehavior = new Gua();
this.flyBehavior = new FlyWithWings();
} @Override
public void display() {
System.out.println("This is RedHeadDuck");
}
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
} }
public class ModelDuck extends Duck {
ModelDuck() {
this.flyBehavior = new FlyNoWay();
this.quackBehavior = new MuteQuack();
}
@Override
public void display() {
System.out.println("This is ModelDuck");
}
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
} }

同时,我们可以在Duck类中增加对FlyBehaviorQuackBehaviorsetter/getter方法,这样我们就可以动态改变鸭子的行为了

public abstract class Duck {
Duck() {} public FlyBehavior flyBehavior;
public QuackBehavior quackBehavior; public abstract void display(); public void swim() {
System.out.println("all ducks can swim");
}
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
} public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
} public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}

测试代码:

public class DuckTest {
public static void main(String[] args) {
Duck redHeadDuck = new RedHeadDuck();
redHeadDuck.display();
redHeadDuck.performFly();
redHeadDuck.performQuack(); System.out.println(); Duck modelDuck = new ModelDuck();
modelDuck.display();
modelDuck.performFly();
modelDuck.performQuack(); System.out.println(); System.out.println("I want that modelduck can fly");
modelDuck.setFlyBehavior(new FlyWithWings());
modelDuck.performFly();
}
}

输出结果:

This is RedHeadDuck
fly fly fly~~~
Gua Gua Gua~~ This is ModelDuck
can not fly
Silence I want that modelduck can fly
fly fly fly~~~

完整代码: Strategy Pattern Source

《Head First 设计模式》之策略模式的更多相关文章

  1. 设计模式:策略模式(Strategy)

    定   义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...

  2. PHP设计模式之策略模式

    前提: 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查 找.排序等,一种常用的方法是硬编码(Hard Cod ...

  3. JavaScript设计模式之策略模式(学习笔记)

    在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选 ...

  4. 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)

    原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...

  5. JavaScript设计模式之策略模式

    所谓"条条道路通罗马",在现实中,为达到某种目的往往不是只有一种方法.比如挣钱养家:可以做点小生意,可以打分工,甚至还可以是偷.抢.赌等等各种手段.在程序语言设计中,也会遇到这种类 ...

  6. 【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查

    原文:使用模板方法设计模式.策略模式 处理DAO中的增删改查 关于模板模式和策略模式参考前面的文章. 分析 在dao中,我们经常要做增删改查操作,如果每个对每个业务对象的操作都写一遍,代码量非常庞大. ...

  7. [design-patterns]设计模式之一策略模式

    设计模式 从今天开始开启设计模式专栏,我会系统的分析和总结每一个设计模式以及应用场景.那么首先,什么是设计模式呢,作为一个软件开发人员,程序人人都会写,但是写出一款逻辑清晰,扩展性强,可维护的程序就不 ...

  8. 设计模式入门,策略模式,c++代码实现

    // test01.cpp : Defines the entry point for the console application.////第一章,设计模式入门,策略模式#include &quo ...

  9. 设计模式之策略模式和状态模式(strategy pattern & state pattern)

    本文来讲解一下两个结构比较相似的行为设计模式:策略模式和状态模式.两者单独的理解和学习都是比较直观简单的,但是实际使用的时候却并不好实践,算是易学难用的设计模式吧.这也是把两者放在一起介绍的原因,经过 ...

  10. python设计模式之策略模式

    每次看到项目中存在大量的if else代码时,都会心生一丝不安全感. 特别是产品给的需求需要添加或者更改一种if条件时,生怕会因为自己的疏忽而使代码天崩地裂,哈哈,本文的目的就是来解决这种不安全感的, ...

随机推荐

  1. 在线浏览PDF之PDF.JS (附demo)

    平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html#skill 下载地址:http://mozilla.gith ...

  2. CSS 选择器及各样式引用方式

    Css :层叠样式表 (Cascading Style Sheets),定义了如何显示HTML元素. 目录 1. 选择器的分类:介绍ID.class.元素名称.符合.层次.伪类.属性选择器. 2. 样 ...

  3. 谱聚类(spectral clustering)原理总结

    谱聚类(spectral clustering)是广泛使用的聚类算法,比起传统的K-Means算法,谱聚类对数据分布的适应性更强,聚类效果也很优秀,同时聚类的计算量也小很多,更加难能可贵的是实现起来也 ...

  4. Aaron Stannard谈Akka.NET 1.1

    Akka.NET 1.1近日发布,带来新特性和性能提升.InfoQ采访了Akka.net维护者Aaron Stannard,了解更多有关Akka.Streams和Akka.Cluster的信息.Aar ...

  5. MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决

    一.简介 MySQL是最流行的开放源码SQL数据库管理系统,它是由MySQL AB公司开发.发布并支持的.有以下特点: MySQL是一种数据库管理系统. MySQL是一种关联数据库管理系统. MySQ ...

  6. 程序猿都没对象,JS竟然有对象?

    现在做项目基本是套用框架,不论是网上的前端还是后端框架,也会寻找一些封装好的插件拿来即用,但还是希望拿来时最好自己过后再回过头了解里面的原理,学习里面优秀的东西,不论代码封装性,还是小到命名. 好吧, ...

  7. 如果你也会C#,那不妨了解下F#(7):面向对象编程之继承、接口和泛型

    前言 面向对象三大基本特性:封装.继承.多态.上一篇中介绍了类的定义,下面就了解下F#中继承和多态的使用吧.

  8. 从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler

    熟悉WebForm开发的朋友一定都知道,Page类必须实现一个接口,就是IHttpHandler.HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...

  9. Android Socket连接PC出错问题及解决

    最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.

  10. OpenGL shader 中关于顶点坐标值的思考

    今天工作中需要做一个事情: 在shader内部做一些空间距离上的计算,而且需要对所有的点进行计算,符合条件的显示,不符合条件的点不显示. 思路很简单,在vertex shader内知道顶点坐标,进行计 ...