掌握了道路后,设计模式,我们将以新的方式来理解设计模式,这种方法更简单、更直观。不信?子就知道了

=====================================================================

DECORATOR模式(以设计模式之道来理解)

【业务】

假设你进入了一个信息安全管理非常严格的公司,这家公司不同意员工自行打印文档。全部的文档打印都须要交给文档打印系统统一管理。文档打印系统会记录每次打印的时间、内容、打印人员。

。。。。

等等。以便兴许出现故障的时候进行追查。

由于公司有非常多的部门,每一个部门的安全要求并不全然一样,同一时候每一个部门关于文档打印也有自己的一些规定。

我们的任务就是要开发一套可以支持整个公司文档打印需求的系统。

【发现变化】

文档打印系统面对的变化主要体如今:文档打印要求是变化的。不同的部门有不同的要求,同一个部门也可能改动自己的打印需求。

比如:

A部门是一个战略规划的部门,里面的资料都非常重要,打印的时候须要在页眉位置打印“绝密”,在页脚的位置打印“密级申明”,同一时候要加上“绝密文档”的水印。

B部门是内部培训部门,打印培训材料的时候须要在页眉位置打印“内部公开”,但不须要密级申明。同一时候加上“培训资料”的水印

C部门是对外宣传部门,打印宣传材料的时候仅仅须要加上“公司logo”的水印。

【传统方法】

传统方法使用类继承来封装打印请求,为每一个部门创建一个打印的子类。详细演示例子代码例如以下:

PrintTask.java -- 文档打印系统开发小组负责维护

package com.oo.designpattern.decorator;

/**
* 打印任务类
*
*/
abstract public class PrintTask { abstract public void print(String text); }

SecretPrint.java -- 文档打印系统开发小组负责维护:

package com.oo.designpattern.decorator;

/**
* 绝密文档的打印
*
*/
public class SecretPrint extends PrintTask{ @Override
public void print(String text) {
Printer.printHeader("绝密");
Printer.printText(text);
Printer.printFooter("本文包括绝密信息,请勿泄露! ");
Printer.printTextWaterMark("绝密文档");
} }

InternalPrint.java -- 文档打印系统开发小组负责维护:

package com.oo.designpattern.decorator;

/**
* 内部公开的文档打印
*
*/
public class InternalPrint extends PrintTask { @Override
public void print(String text) {
Printer.printHeader("内部公开");
Printer.printText(text);
Printer.printTextWaterMark("培训资料");
} }

PublicPrint.java -- 文档打印系统开发小组负责维护:

package com.oo.designpattern.decorator;

import java.awt.Image;

/**
* 对外宣传的文档打印
*
*/
public class PublicPrint extends PrintTask { private Image _logo;
@Override
public void print(String text) {
Printer.printText(text);
Printer.printImgWaterMark(_logo);
} }

文档打印系统实现例如以下:

PrintServer -- 文档打印系统开发小组负责维护

package com.oo.designpattern.decorator;

/**
* 文档打印系统
*
*/
public class PrintServer { /**
* 运行打印任务
* @param task
* @param text
*/
public static void executePrintTask(PrintTask task, String text){
log();
task.print(text);
audit();
} /**
* 记录日志
*/
private static void log(){
//省略详细实现代码
} /**
* 记录审计相关信息
*/
private static void audit(){
//省略详细实现代码
}
}

定义好不同的打印任务后,每一个部门依据自己的须要,选择不同的任务发给文档打印系统。

比如,A部门的打印处理例如以下:

SecretDepartment.java  -- A部门负责维护

package com.oo.designpattern.decorator;

/**
* A部门的打印处理
*
*/
public class SecretDepartment { public void print(String text){
PrintTask task = new SecretPrint(); //PrintServer即“文档打印系统”
PrintServer.executePrintTask(task, text);
}
}

传统方法使用类继承来封装变化的打印需求,当面对变化时,存在例如以下问题:

1)新增部门的时候。须要文档打印系统提供一个新的打印任务类,将导致出现大量的***Print类;

比如:新建了一个D部门,D部门仅仅须要打印纯文本就可以,那么已有的SecretPrint、InternalPrint、PublicPrint类都无法满足需求。必须新增一个PurePrint的类;

2)某个部门的打印需求变更的时候,须要改变已有的***Print类;

比如:C部门希望在对外宣传材料的页眉上打印公司名称,则须要改动PublicPrint类。

【设计模式方法】

设计模式封装变化的方法就是Decorator模式。

Decorator模式定义例如以下:

“动态的给一个对象加入一些额外的职责”

《设计模式》一书中关于Decorator模式的描写叙述并不非常直观,我理解Decorator模式为“通过聚合的方式将动态变化的职责组合起来”。

我们详细看看Decorator模式是怎样封装变化的。

首先,将变化的职责封装为独立的类。传统方式实现中,不同的职责是相应不同的函数调用,而设计模式中,不同的职责是不同的类;

其次,通过聚合将变化的职责组合起来。传统方式中,不同职责的组合是通过在一个函数中写多行代码来体现的。而设计模式中,通过对象的聚合将不同职责组合起来。

【Decorator模式结构】

Component:定义一个对象接口(相应结构图中的operation函数),可以给这些对象动态加入职责

ConcreteComponent:定义一个对象,这个对象是实际的Component。将被Decorator修饰

Decorator:定义修饰对象的接口。Decorator实现的关键在于聚合了一个Component对象

ConcreteDecorator:详细的修饰对象

【代码实现】

使用Decorator设计模式实现的文档打印系统代码例如以下:

*********************类设计*****************************

PrintComponent.java -- 文档打印系统开发小组负责维护

package com.oo.designpattern.decorator2;

/**
* 打印组件的父类
*
*/
abstract public class PrintComponent { abstract public void print();
}

PrintDecorator.java -- 文档打印系统开发小组负责维护

package com.oo.designpattern.decorator2;

/**
* 修饰的打印任务。相应Decorator模式中的Decorator
* Decorator可以聚合ConcreteComponent或者其他Decorator
* 这样可以使得打印任务可以嵌套运行下去。直到最后完毕全部打印任务
*
*/
public abstract class PrintDecorator extends PrintComponent { abstract public void print();
}

TextComponent.java -- 文档打印系统开发小组负责维护

package com.oo.designpattern.decorator2;

import com.oo.designpattern.decorator.Printer;

/**
* 文本打印,相应Decorator模式中的ConcreteComponent
* 打印任务到ConcreteComponent就算真正完毕了
*
*/
public class TextComponent extends PrintComponent { private String _text;
TextComponent(String text){
this._text = text;
} @Override
public void print() {
Printer.printText(this._text);
}
}

HeaderDecorator.java -- 文档打印系统开发小组负责维护

package com.oo.designpattern.decorator2;

import com.oo.designpattern.decorator.Printer;

/**
* 页眉打印
*
*/
public class HeaderDecorator extends PrintDecorator { private PrintComponent _comp; //被修饰的打印组件
private String _text; //须要打印的页眉内容 /**
* 初始化的时候,必须包括其他打印组件comp。这是实现Decorator模式的前提
* 同一时候也须要指定当前组件所需的參数。不能在print函数的參数中指定,
* 由于每一个Decorator所需的參数是不一样的
* @param comp
* @param text
*/
HeaderDecorator(PrintComponent comp, String text) {
this._comp = comp;
this._text = text;
} /**
* 打印
*/
@Override
public void print() { //打印的时候将当前Decorator和被修饰的Component分开,这是Decorator模式的关键
Printer.printHeader(_text); //打印页眉 //_comp本身假设是Decorator。就会嵌套打印下去
//_comp本身假设不是Decorator,而是ConcreteComponent,则打印任务到此结束
_comp.print();
}
}

FooterDecorator.java

package com.oo.designpattern.decorator2;

import com.oo.designpattern.decorator.Printer;

/**
* 页脚打印。和页眉打印相似。此处省略同样的凝视代码
*
*/
public class FooterDecorator extends PrintDecorator { private PrintComponent _comp;
private String _text; FooterDecorator(PrintComponent comp, String text) {
this._comp = comp;
this._text = text;
} /**
* 打印
*/
@Override
public void print() { Printer.printFooter(_text); //打印页脚 _comp.print();
}
}

TextWatermarkDecorator.java

package com.oo.designpattern.decorator2;

import com.oo.designpattern.decorator.Printer;

/**
* 文本水印打印。和页眉打印相似,此处省略同样的凝视代码
*
*/
public class TextWatermarkDecorator extends PrintDecorator{ private PrintComponent _comp;
private String _text; TextWatermarkDecorator(PrintComponent comp, String text) {
this._comp = comp;
this._text = text;
} /**
* 打印
*/
@Override
public void print() { Printer.printTextWaterMark(_text); //打印文本水印 _comp.print();
} }

ImgWatermarkDecorator.java

package com.oo.designpattern.decorator2;

import java.awt.Image;

import com.oo.designpattern.decorator.Printer;

/**
* 图片水印打印,和页眉打印相似,此处省略同样的凝视代码
*
*/
public class ImgWatermarkDecorator extends PrintDecorator { private PrintComponent _comp;
private static Image _logo; //图片水印仅仅能是公司logo ImgWatermarkDecorator(PrintComponent comp) {
this._comp = comp;
} /**
* 打印
*/
@Override
public void print() { Printer.printImgWaterMark(ImgWatermarkDecorator._logo); //打印图片水印 _comp.print();
} }

PrintServer.java

package com.oo.designpattern.decorator2;

public class PrintServer {

    /**
* 运行打印任务
* @param comp
*/
public static void executePrintTask(PrintComponent comp){
log();
comp.print();
audit();
} /**
* 记录日志
*/
private static void log(){
//省略详细实现代码
} /**
* 记录审计相关信息
*/
private static void audit(){
//省略详细实现代码
}
}

*********************类使用*****************************

A部门的打印处理例如以下(例如以下代码请细致阅读,特别是凝视部分):

SecretDepartment.java  -- A部门负责维护

package com.oo.designpattern.decorator2;

/**
* A部门的打印处理,注意与传统方法中的SecretDepartment类对照
*
*/
public class SecretDepartment { /**
* 打印任务1。相应传统方式的SecretePrint类
* @param text
*/
public void print(String text){ /**
* 使用Decorator设计模式后。打印任务不再是一个单独的类SecretPrint类,
* 而是通过将多个打印项目聚合成一个打印任务
*/
PrintComponent textComp = new TextComponent(text); //注意header聚合了textComp
PrintDecorator header = new HeaderDecorator(textComp, "绝密");
//注意footer聚合了header,而不是textComp,这样就行嵌套运行下去
PrintDecorator footer = new FooterDecorator(header, "本文包括绝密信息,请勿泄露! ");
//注意watermark聚合了footer,而不是textComp。这样就行嵌套运行下去
PrintDecorator watermark = new TextWatermarkDecorator(footer, "绝密文档"); //PrintServer即“文档打印系统”,与传统的PrintServer相比,这里不须要知道打印的text内容
//text内容已经封装到TextComponent中去了(相应代码行14行)
PrintServer.executePrintTask(watermark); //注意这里传递给打印系统的是最后一个Decorator对象watermark
} /**
* A部门的第二个打印任务,将文本水印改为图片水印,而且不再打印页脚
* @param text
*/
public void print2(String text){ /**
* 新增打印任务。无需文档管理系统添加新的类,仅仅要A部门自己改动代码就可以
*/
PrintComponent textComp = new TextComponent(text); //注意header聚合了textComp
PrintDecorator header = new HeaderDecorator(textComp, "绝密");
//注意watermark聚合了header。而不是textComp,这样就行嵌套运行下去
PrintDecorator watermark = new ImgWatermarkDecorator(header); PrintServer.executePrintTask(watermark);
}
}

可以看到,使用了设计模式的方法后。打印业务的变化,可以通过相似数学上的排列组合已有的打印功能来完毕,而不再须要新的打印类了。

================================================ 
转载请注明出处:http://blog.csdn.net/yunhua_lee/article/details/38865605
================================================

版权声明:本文博客原创文章,博客,未经同意,不得转载。

连载:面向对象的葵花宝典:思维、技能与实践(40) - DECORATOR模式的更多相关文章

  1. 《连载 | 物联网框架ServerSuperIO教程》- 5.轮询通讯模式开发及注意事项。附:网友制作的类库说明(CHM)

    1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...

  2. 《连载 | 物联网框架ServerSuperIO教程》- 8.单例通讯模式开发及注意事项

    1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...

  3. [.net 面向对象程序设计深入](24)实战设计模式——策略模式(行为型)

    [.net 面向对象程序设计深入](24)实战设计模式——策略模式(行为型) 1,策略模式定义 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它 ...

  4. [.net 面向对象程序设计深入](26)实战设计模式——策略模式 Strategy (行为型)

    [.net 面向对象程序设计深入](26)实战设计模式——策略模式 Strategy (行为型) 1,策略模式定义 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模 ...

  5. 面向对象程序设计(OOP设计模式)-结构型模式之装饰器模式的应用与实现

    课程名称:程序设计方法学 实验4:OOP设计模式-结构型模式的应用与实现 时间:2015年11月18日星期三,第3.4节 地点:理1#208 一.实验目的 加深对结构型设计模式的理解以及在开发中的实际 ...

  6. 连载:面向对象的葵花宝典:思考、技巧与实践(39) - 设计原则 vs 设计模式

    它的设计原则,和设计模式,是否该用它? ============================================================================= 在& ...

  7. 《连载 | 物联网框架ServerSuperIO教程》1.4种通讯模式机制。附小文:招.NET开发,结果他转JAVA了,一切都是为了生活

    参考文章: 1.SuperIO通讯框架介绍,含通信本质 2.C#跨平台物联网通讯框架ServerSuperIO(SSIO) 一.感慨 上大学的时候,没有学过C#,花了5块钱在地坛书市买了一本教程,也就 ...

  8. PHP 面向对象编程和设计模式 (3/5) - 单例模式和工厂模式

    PHP高级程序设计 学习笔记 2014.06.11 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容 ...

  9. [转载]基于TFS实践敏捷-Scrum模式运用

    根据Forrester Research今年第二季度的一份研究报告,在超过1000名专业开发人员中,采用敏捷模式进行软件开发的已经有10.9%采用了Scrum模式,在所有的敏捷开发模式中名列首位,而在 ...

随机推荐

  1. Android 随着输入框控件的清除功能ClearEditText,抄IOS输入框

    今天给大家带来一个非常有用的小控件ClearEditText,就是在Android系统的输入框右边增加一个小图标,点击小图标能够清除输入框里面的内容,IOS上面直接设置某个属性就能够实现这一功能.可是 ...

  2. 非常基本的SQL 内外连接

    有些问题一直很郁闷,例如:为什么会存在大约在同一时间连接这个东西.如果外键为空,创建问题的声明时,将有一个外键约束失败. 后来,在精心研究,恩.外部连接(左连接.正确的连接). 事实上都是非常基础的东 ...

  3. Java知多少(87)选择框和单选按钮(转)

    选择框.单选框和单选按钮都是选择组件,选择组件有两种状态,一种是选中(on),另一种是未选中(off),它们提供一种简单的 “on/off”选择功能,让用户在一组选择项目中作选择. 选择框 选择框(J ...

  4. IE按F12,开发者工具已经在最低点,那么国家就不会出错

    ie浏览器.按F12,开发工具将问世. 没有,试试下面的方法就可以解决: 开开发者工具图标,它会出来缩略图,于缩略图右键点-你可以最大限度地提高.然后选择IE8兼容模式可 版权声明:本文博主原创文章. ...

  5. Mongodb安装和配置

    Mongodb之安装配置 安装 Mongodb的下载地址为Mongodb官网.下载时.你能够选择是安装包或者是压缩包. 下载完毕后.双击安装包并安装. 安装完毕后.你能够在安装文件夹看到下图中所见的文 ...

  6. JDK5什么是新的堵塞队列线程(四)

    一. 堵塞队列与普通队列: 队列是一种主要的数据类型,其典型特征是先进先出. 堵塞队列和普通队列的差别在于: 当队列为空时.从队列中获取元素的线程会被堵塞.直到其它的线程往空的队列里插入新的元素: 当 ...

  7. 【Java基础】对象的具体创建过程

    所有的类(以Dog类为例)在第一次使用时,动态的加载到JVM中,当首次创建Dog对象时,或者是Dog类的静态方法.静态属性域在第一次被访问时,JVM解释器查找到classpath,定位到Dog.cla ...

  8. Ant—Ant标签解释

            采用ant命令必须写ant命令脚本,脚本由非常多Ant标签组成.现在总结一下我也遇到过Ant标签: 版权声明:本文博主原创文章,博客,未经同意不得转载.

  9. Android开发技巧——PagerAdapter再简单的包

    再次内容View的ViewPager该适配器PagerAdapter简包,支持List数据与SparseArray数据.随着更新的浏览功能. 首先,首先贴上顶部抽象类代码: /* * Date: 14 ...

  10. iOS如何添加照片模拟器(附带诉讼)

    刚開始做图片选择时,使用了最笨的办法给iphone模拟器添加照片. 方法一:首先打开safari.然后找到图片.点击图片,保存到本地(iphone): 方法二:拖动本地计算机的随意一张照片到iphon ...