设计模式入门——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 " ...
随机推荐
- HDOJ 2002 计算球体积
#include<cstdio> #define PI 3.1415927 int main() { double r; while (scanf_s("%lf", & ...
- [UE4]射击产生弹孔:Spawn Decal At Location、Spawn Decal Attached
Spawn Decal At Location.Spawn Decal Attached 在指定的位置生成一个材质贴上去 产生随意旋转角度
- Java集合类分析,初始化
Java集合是常用的数据类型,在此详细分析接口和实现类.整个集合框架就围绕一组标准接口而设计,学习集合框架有助开发实践. 框架体系图 1.Collection 接口Collection 是最基本的集合 ...
- HTTP协议的简单解析
超文本传输协议(HTTP,HyperText Transfer Protocol)是用于从服务器传输超文本到本地浏览器的传输协议,是应用最为广泛的网络协议.B/S网络架构的核心是HTTP,掌握HTTP ...
- 高通9X07模块QMI架构使用入门
QMI(Qualcomm Message Interface) 高通用来替代OneRPC/DM的协议,用来与modem通信.本文是摸索高通QMI机制一点经验,重点解读了如果建立拨号连接,仅供参考.qm ...
- vue2.0-组件传值
父组件给子组件传值,子组件用props接收 例子:两个组件,一个是父组件标签名是parent,一个是子组件标签名是child,并且child组件嵌套在父组件parent里,大概的需求是:我们子组件里需 ...
- tomcat简单使用(一)
先来说一说tomcat的使用 官网下载tomcat:tomcat,我的百度云上的:tomcat Tomcat分为安装版和解压版:安装版:一台电脑上只能安装一个Tomcat:解压版:无需安装,解压即可用 ...
- 【原创】重装Windows系统后Android studio无需重装,直接迁移
每次重装Windows系统后重装各种开发环境让人苦不堪言,比如VS2013 +补丁,没有个小半天根本搞不定! 对与Android的开发者,同样安装JDK+Android Studio + Adnroi ...
- day6作业(元组,字典,集合)
默写: 1.元组 字典 集合 列表 各自的特点 2.字典添加 删除 修改 循环 必做: 1.餐厅提供了五种不同的菜,使用元组来存储他们,并循环打印出所有菜名,要求用户输入新加的菜名,加入到菜单中,并重 ...
- 【Eclipse】eclipse自动提示+自动补全
解决代码的自动提示问题: 1.打开 Eclipse -> Window -> Perferences 2.找到Java 下的 Editor 下的 Content Assist , 右边出现 ...