设计模式入门——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 " ...
随机推荐
- C#一年中有多少周方法和js一年中第几周
最近在做一个时间插件,用的是jquery-daterangepicker ,现在分享一下查询时间是一年中的第几周的js方法 和 一年中有多少周的C#后台方法,默认是按照周一为一周的开始,如果一年的第 ...
- MySQL 捕获有问题的SQL-慢查日志 实例
启动MySQL慢查日志 set global show_query_log_file = /sql_log/show_log.log set global log_queries_not_using_ ...
- MySQL之 Mysqldump导出数据库
参数大全 参数说明 --all-databases , -A 导出全部数据库. mysqldump -uroot -p --all-databases --all-tablespaces , -Y 导 ...
- 成功设置open live writer
mark一下,哈哈哈 https://www.cnblogs.com/chrisrockdl/
- bootstrap样式
图片: <img src="w.jpg" alt="" class="img-rounded"><img src=&quo ...
- $.extend与$.fn.extend()
很多情况下,用户需要对jQuery插件进行二次开发,那么我们来看看JQ原开发者为我们提供的两种扩展插件的方式如下: 1.类别类:相当于为jquery扩展一个类,比如现在我要扩展一个简单的想加的功能函数 ...
- 释放linux的buff/cache
有个linux的服务器,2G内存的,今天登上去一看,内存竟然被占得满满的. ssh上去执行了free. free -m total used free shared buff/cache availa ...
- python中的sockeserver模块简单实用
1. socketserver模块简介 在python的socket编程中,实用socket模块的时候,是不能实现多个连接的,当然如果加入其它的模块是可以的,例如select模块,在这里见到的介绍下s ...
- 【Git+Docker】Docker初期学习认识和安装配置详解
Docker: 特性: 1.以应用为中心 2.自动化构建 3.版本控制 4.组件重用 5.镜像共享 6.工具生态系统 具体后续学习 优势: 1.文件系统隔离 2.进程隔离 3.网络隔离 4.资源隔离和 ...
- js中的面向对象--类似于类的概念
创建对象的几种常用方式 1.使用Object或对象字面量创建对象 2.工厂模式创建对象 3.构造函数模式创建对象 4.原型模式创建对象 1.使用Object或对象字面量创建对象 使用object va ...