设计模式是被前人发现、经过总结形成了一套某一类问题的一般性解决方案。使用模式最好的方式是:把模式装进脑子,然后在设计和已有的应用中,寻找何处可以使用它们。以往是代码复用,现在是经验复用。

从模拟鸭子游戏说起

初始需求:各种鸭子(野鸭MallardDuck、红头鸭RedheadDuck等),一边游泳swim,一边呱呱叫quack,每种鸭子外观都不同display。

初始方案:设计一个鸭子超类,并让各种鸭子继承此超类。

需求变更:让鸭子能够飞fly。

方案1:在Duck类中加上fly()。

结果:所有鸭子都继承fly,但并非所有鸭子都会飞,比如橡皮鸭RubberDuck(继承牵一发动全身)。

方案1_1:对于不能飞的鸭子,在子类中覆盖fly()。

结果:每当有新的鸭子出现,就要被迫检查并可能需要覆盖fly()。同理,对于叫声quack也一样。

方案2:把fly()和quack()从超类中取出,放进Flyable和Quackable接口中,只会飞的鸭子实现Flyable,会叫的实现Quackable。

结果:不会再有会飞的橡皮鸭,但由于接口不具有实现代码,造成代码无法复用(接口无法达到代码复用)。

方案2_1:设计两个接口FlyBehavior和QuackBehavior,还有它们对应的类,负责实现具体行为。

结果:飞行和呱呱叫动作可以被其他的对象复用,因为这些行为已经与鸭子类无关;可以新增一些行为,不会影响到既有的行为类,也不会影响使用飞行行为的鸭子类(有了继承的复用好处,没了继承所带来的包袱)。

完善方案2_1:在Duck类中加入两个变量“flyBehavior”和“quackBehavior”,声明为接口类型,用performFly和performQuack分别取代fly和quack;同时加入两个新方法setFlyBehavior和setQuackBehavior,用来随时改变鸭子的行为。

测试Duck的代码

Duck类(Duck.java)

public abstract class Duck {
//所有鸭子子类都继承它
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck(){
}
public abstract void display(); public void perfmormFly(){
//委托给行为类
flyBehavior.fly();
}
public void performQuack(){
//委托给行为类
quackBehavior.quack();
}
public void setFlyBehavior(FlyBehavior fb){
flyBehavior=fb;
}
public void setQuackBehavior(QuackBehavior cb){
quackBehavior=cb;
}
public void swim(){
System.out.println("All ducks float,even decoys!!");
}
}

MallardDuck类和ModelDuck类(MallardDuck.java与ModelDuck)

public class MallardDuck extends Duck{
public MallardDuck(){
quackBehavior=new Quack();
flyBehavior=new FlyWithSwings();
}
public void display(){
System.out.println("I'm a real Mallard Duck");
}
} public class ModelDuck extends Duck{
public ModelDuck(){
flyBehavior=new FlyNoWay();
quackBehavior=new MuteQuack();
}
public void display(){
System.out.println("I'm a model duck!!");
}
}

FlyBehavior接口(FlyBehavior.java)与三个行为实现类(FlyWithWings.java、FlyNoWay.java和新增的FlyRocketPowered.java)

public interface FlyBehavior {
public void fly();
} public class FlyWithSwings 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 class FlyRocketPowered implements FlyBehavior{
public void fly(){
System.out.println("I'm flying with a rocket!!");
}
}

QuackBehavior接口(QuackBehavior.java)及其三个实现类(Quack.java、MuteQuack.java、Squeak.java)

 public interface QuackBehavior {
public void quack();
} public class Quack implements QuackBehavior{
public void quack(){
System.out.println("Quack!!");
}
} public class MuteQuack implements QuackBehavior{
public void quack(){
System.out.println("Silence!!");
}
} public class Squeak implements QuackBehavior{
public void quack(){
System.out.println("Squeak");
}
}

测试类(MiniDuckSimulator.java)

public class MiniDuckSimulator {
public static void main(String[] args) {
// TODO Auto-generated method stub
Duck mallard=new MallardDuck();
mallard.perfmormFly();
mallard.performQuack();
Duck model=new ModelDuck();
model.perfmormFly();
model.performQuack();
model.setFlyBehavior(new FlyRocketPowered());
model.perfmormFly();
}
}
/*
*
* 运行结果:
* Quack!!
* I can't fly!!
* Silence!!
* I'm flying with a rocket!!
*/

这就是策略模式

策略模式(Strategy Pattern)定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。封闭可以互换的行为,并使用委托来决定要使用哪一个。

策略模式结构

Strategy:可由接口或抽象类来实现;定义所有支持的算法的公共接口;Context使用这个接口来调用某ConcreteStrategy定义的算法。

ConcreteStrategy:具体的策略实现,也就是具体的算法实现。

Context:用一个ConcreteStrategy对象来配置;维护一个对Strategy对象的引用;可定义一个接口来让Strategy访问它的数据。

策略模式示例代码

/**
* 策略,定义算法的接口
*/
public interface Strategy {
// 某个算法的接口,可以有传入参数,也可以有返回值
public void algorithmInterface();
} /**
* 实现具体的算法
*/
public class ConcreteStrategyA implements Strategy {
public void algorithmInterface() {
//具体的算法实现
}
}
public class ConcreteStrategyB implements Strategy {
public void algorithmInterface() {
//具体的算法实现
}
}
public class ConcreteStrategyC implements Strategy {
public void algorithmInterface() {
//具体的算法实现
}
} /**
* 上下文对象,通常会持有一个具体的策略对象
*/
public class Context {
//持有一个具体的策略对象
private Strategy strategy; // 构造方法,传入一个具体的策略对象
//@param aStrategy 具体的策略对象
public Context(Strategy aStrategy) {
this.strategy = aStrategy;
} // 上下文对客户端提供的操作接口,可以有参数和返回值
public void contextInterface() {
//通常会转调具体的策略对象进行算法运算
strategy.algorithmInterface();
}
}

关于策略模式, 最后推荐一篇博文:http://www.uml.org.cn/sjms/201009092.asp

设计模式入门——Head First的更多相关文章

  1. 基于java的设计模式入门(1)——为什么要学习设计模式

    大年初一,楼主在这里给大家拜年,祝大家码上升职加薪,码上有对象结婚,码上有车有房,幸福安康. 过完年,回学校注册报道之后,大概就要回深圳到公司开始实习了.提高自己,无非就有两种方式,一是看书学习,二是 ...

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

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

  3. 写给Python初学者的设计模式入门

    有没有想过设计模式到底是什么?通过本文可以看到设计模式为什么这么重要,通过几个Python的示例展示为什么需要设计模式,以及如何使用. 设计模式是什么? 设计模式是经过总结.优化的,对我们经常会碰到的 ...

  4. HeadFirst学习笔记-1. 设计模式入门

    1.概念 在开始学习前,我们先了解一些概念,方便我们接下来的学习. OO基础 抽象 继承 多态 封装 OO原则 封装变化 多用组合,少用继承 针对接口编程,不针对实现编程 设计模式 设计模式(Desi ...

  5. 设计模式入门,适配器模式,c++代码实现

    // test07.cpp : Defines the entry point for the console application.// #include "stdafx.h" ...

  6. 设计模式入门,命令模式,c++代码实现

    // test06.cpp : Defines the entry point for the console application.////设计模式第5章 命令模式#include "s ...

  7. 设计模式入门,单件模式,c++代码实现

    // test05.cpp : Defines the entry point for the console application.// #include "stdafx.h" ...

  8. 设计模式入门,工厂模式,c++代码实现

    // test04.cpp : Defines the entry point for the console application.////设计模式第4章 工厂模式#include "s ...

  9. 设计模式入门,装饰着模式,c++代码实现

    // test03.cpp : Defines the entry point for the console application.////设计模式第3章 装饰者模式#include " ...

随机推荐

  1. Java的Start和Runnable方法的区别

    两种方法的区别 1) start:用法:start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码.通过调用Thread类的start()方法来启动一 ...

  2. 数据迁移_把RAC环境备份的数据,恢复到另一台单机Oracle本地文件系统下

    数据迁移_把RAC环境备份的数据,恢复到另一台单机Oracle本地文件系统下 作者:Eric 微信:loveoracle11g 1.创建pfile文件 # su - ora11g # cd $ORAC ...

  3. 【TensorFlow学习笔记 】name_socpe variable_scope

    [引言]TensorFlow中的命名域是非常重要的概念,涉及到参数共享,方便命名参数管理,定义图结构 本文主要介绍name_scope 和 variable_scope,slim包中的arg_scop ...

  4. C# DataGirdview手动添加数据,导出txt文件并自动对齐

    //DataGirdview手动添加数据 private void btnDataGirdView_Click(object sender,EventArgs e) {       dataGridV ...

  5. tcp粘包解决

    import socket import hashlib import subprocess import struct phone = socket.socket(socket.AF_INET,so ...

  6. 网络基础和python(二)

    一,五层协议 应用层    端口 传输层   tcp\udp 网络层   ipv4\6 数据链路层  ethernet 物理层    mac 二:什么是变量? 变量:核心在于变和量儿字,变->变 ...

  7. Json1:使用gson解析、生成json

    Json解析: 1.json第三方解析包:json-lib.gson.jackson.fastjson等2.Google-gson只兼容jdk1.5版本以上:JSON-lib分别支持1.4和1.53. ...

  8. vue 要点

    一: 1.  如果在实例创建之后添加新的属性到实例上,它不会触发视图更新. 2.  v-show 的元素会始终渲染并保持在 DOM 中.v-show 是简单的切换元素的 CSS 属性 display.

  9. 微信小程序 setData 的坑(转)

    最近在使用微信小程序的setData时,遇到了以下问题.如下: 官网文档在使用setData()设置数组对象的某个元素的属性时,是这么使用的: Page({ data: { array: [{text ...

  10. hadoop2.4集群的搭建

    hadoop中的三大组件: hdfs:分布式文件管理系统 (namenode管理所有的datanode) yarn:资源调度系统(ResourceManager管理所有的nodemanager) ma ...