设计模式入门——Head First
设计模式是被前人发现、经过总结形成了一套某一类问题的一般性解决方案。使用模式最好的方式是:把模式装进脑子,然后在设计和已有的应用中,寻找何处可以使用它们。以往是代码复用,现在是经验复用。
从模拟鸭子游戏说起
初始需求:各种鸭子(野鸭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的更多相关文章
- 基于java的设计模式入门(1)——为什么要学习设计模式
大年初一,楼主在这里给大家拜年,祝大家码上升职加薪,码上有对象结婚,码上有车有房,幸福安康. 过完年,回学校注册报道之后,大概就要回深圳到公司开始实习了.提高自己,无非就有两种方式,一是看书学习,二是 ...
- 设计模式入门,策略模式,c++代码实现
// test01.cpp : Defines the entry point for the console application.////第一章,设计模式入门,策略模式#include &quo ...
- 写给Python初学者的设计模式入门
有没有想过设计模式到底是什么?通过本文可以看到设计模式为什么这么重要,通过几个Python的示例展示为什么需要设计模式,以及如何使用. 设计模式是什么? 设计模式是经过总结.优化的,对我们经常会碰到的 ...
- HeadFirst学习笔记-1. 设计模式入门
1.概念 在开始学习前,我们先了解一些概念,方便我们接下来的学习. OO基础 抽象 继承 多态 封装 OO原则 封装变化 多用组合,少用继承 针对接口编程,不针对实现编程 设计模式 设计模式(Desi ...
- 设计模式入门,适配器模式,c++代码实现
// test07.cpp : Defines the entry point for the console application.// #include "stdafx.h" ...
- 设计模式入门,命令模式,c++代码实现
// test06.cpp : Defines the entry point for the console application.////设计模式第5章 命令模式#include "s ...
- 设计模式入门,单件模式,c++代码实现
// test05.cpp : Defines the entry point for the console application.// #include "stdafx.h" ...
- 设计模式入门,工厂模式,c++代码实现
// test04.cpp : Defines the entry point for the console application.////设计模式第4章 工厂模式#include "s ...
- 设计模式入门,装饰着模式,c++代码实现
// test03.cpp : Defines the entry point for the console application.////设计模式第3章 装饰者模式#include " ...
随机推荐
- jqgrid使用(1)生成表格
1.引入js,css 2,基本配置 function init() { $("#list1").jqGrid({ url: "../Listing.ashx", ...
- sas 获取字符串长度实例
data _null_;a='Dogcat';b=' Dog cat';c=' Dog cat ';Ra=length(a);Rb=length(b);Rc=length(c);put Ra=Rb ...
- All entities must be found CRM客户责任人变更报错
问题: 1 修改客户的责任人时,报错. 修改其它字段正常. 2 有的客户可以修改,有的不能修改. 使用 Trace Log 查到的信息: All entities must be found. 原因: ...
- linux系统配置jdk环境
前提:linux服务器+JDK8-linux版本 工具:FileZilla+Xshell 将jdk上传到服务器的某个文件夹(本人是JDK) 进入该文件夹,输入tar xzvf jdk-8u77-li ...
- ThreadException
在windows窗体程序中,使用 ThreadException 事件来处理 UI 线程异常,使用 UnhandledException 事件来处理非 UI 线程异常.ThreadException可 ...
- boost 学习笔记 1: lexical_cast
参考原著地址:http://einverne.github.io/post/2015/12/boost-learning-note-1.html 转换对象要求 lexical_cast 对转换对象有如 ...
- CS229 6.12 Neurons Networks from self-taught learning to deep network
self-taught learning 在特征提取方面完全是用的无监督的方法,对于有标记的数据,可以结合有监督学习来对上述方法得到的参数进行微调,从而得到一个更加准确的参数a. 在self-taug ...
- 小朋友学C语言(6)
(一) 先动手编写一个程序: #include <stdio.h> int main() { if(1) { printf("The condition is true!\n&q ...
- uWSGI, Gunicorn, 啥玩意儿?
因为nginx等优秀的开源项目,有不少本来不是做服务器的同学也可以写很多服务器端的程序了.但是在聊天中会发现,大家虽然写了不少代码,但是对wsgi是什么,gunicorn是什么,反向代理又是什么并不了 ...
- phpmyadmin无登录表单无法登陆
发现我的博客的phpmyadmin登录过一次成功之后,后面在登录没有登录表单了,查了很多原因,下面的方法亲测可以解决 打开 phpMyAdmin\libraries\plugins\auth\Auth ...