面向对象程序设计(OOP设计模式)-结构型模式之装饰器模式的应用与实现
课程名称:程序设计方法学
实验4:OOP设计模式-结构型模式的应用与实现
时间:2015年11月18日星期三,第3、4节 地点:理1#208
一、实验目的
加深对结构型设计模式的理解以及在开发中的实际应用能力。
二、实验内容
众所周知,开店的申请手续是很繁琐的。以个体工商户开一家小餐馆为例,首先要拿身份证原件及复印件到当地工商所登记名称,然后凭登记的名称分别到辖区内的环保部门和卫生监督所去申领排污许可证和卫生许可证。拿到这两个证后,再凭这两个证及相应的房屋租赁证明、身份证,去工商所申请领取工商营业执照。此外,在开业之前,还需要向消防部门进行消防审批,向当地税务局申请领取地税税务登记号。这些步骤中,有些有严格的先后顺序,有些则是可以同时进行的。此外,根据所开店铺的具体类型,可能还有一些额外的审批手续要办。(比如开药店,还需要向当地的药监局申领药品经营许可证)。
针对以上说明,现在要求你设计一个开店审批工作流管理系统,实现对上述审批流程的自动化管理。要求使该系统实现审批步骤的动态组合和叠加,并具有较强的可扩展性。
请你选择适当的面向对象设计模式,使用面向对象的建模方法,给出上述系统的设计,使其在满足基本需求的前提下具有最佳的可扩展性。
要求:
实验报告中要求绘制UML类图,给出设计中各个类的主要成员,并附以适当的文字说明详细描述每个类的作用;
实验报告中应针对上述设计,给出使用C++(或java)实现的完整的示意性代码,以及在本地计算机上调试、运行该程序的截图(要求截图的结果中能体现个人的学号、姓名等信息)。
实验报告的末尾请对所用的设计模式、该模式的优缺点及使用心得等做简要小结。
附加要求:
对于我们所介绍的常见的几种结构型的设计模式,你能不能也举出这些模式的一些应用实例,并给出相关的UML类图说明呢?
三、实验环境
硬件条件:微机
操作系统:Windows 2007
开发环境:Eclipse,Rational Rose 2003
四、实验步骤和结果
(一)选择适当的面向对象设计模式
由题意,要求设计一个开店审批工作流管理系统,在开店审批的流程中,开店者需要不断的去申请证书,这就相当于给店铺不断的附加上不同的许可证书。依据开店的申请手续,各个步骤之间有些有严格的先后顺序,有些则是可以同时进行的。而且,根据所开店铺的具体类型,可能还有一些额外的审批手续要办。因此,在原有的店铺审批申请流程的基础上,为其添加装饰器组件进行具体手续的办理。故,为实现对上述审批流程的自动化管理,且使该系统实现审批步骤的动态组合和叠加、具有较强的可扩展性,则选用的是结构型设计模式中的装饰器模式。即可以使用在需要增加一些功能的排列组合而产生其他的功能。因此可以将各类许可证书看成具体的装饰角色,负责给店铺添加开店必备的证书,将店铺看成一个具体构件角色,用来接收附加给他的装饰品,即证书。
(二)UML类图的设计和绘制
设计分析:
装饰器模式是以对客户透明的方式动态的给对象附加上更多的功能,是继承关系的一个替代方案。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。装饰器模式中的角色有:
1、 抽象可视化组件(VisualComponent)角色:给出一个抽象接口,以规范准备接收附加功能的对象。
2、 具体组件角色(ConcreteCompont)角色:用来定义一个将要接收附加功能的类。
3、 装饰器(Decorato)角色:持有一个组件(VisualComponent)对象的实例,并定义一个与抽象组件接口一致的接口。
4、 具体装饰器(ConcreteDecorator)角色:负责为组件对象实现附加的功能。
(图1 一般的装饰器模式的UML类图 )
(图2该开店审批工作流管理系统的装饰器模式的UML类图)
(三)针对上述设计,用java实现的完整的示意性代码如下所示:
Java 类的建立如下所示:
1、VisualComponent接口,即可视化组件接口, 该抽象接口规范准备接收附加责任的对象。
package com.shen.decorator;
//VisualComponent接口,即可视化组件接口, 该抽象接口规范准备接收附加责任的对象
public interface VisualComponent {
public void Operation();
}
2、ShopApprovalProcess 开店审批工作流类,继承自父类VisualComponent可视化组件类。
package com.shen.decorator;
//ShopApprovalProcess 开店审批工作流类,继承自父类VisualComponent可视化组件类
public class ShopApprovalProcess implements VisualComponent{
@Override
public void Operation() {
System.out.println("***欢迎来到【开店审批工作流管理系统】_105032013120***");
}
}
3、Decorator装饰器类,继承自父类VisualComponent可视化组件类,用于对开店审批工作流管理系统的组件装饰作用。
package com.shen.decorator;
//Decorator装饰器类,继承自父类VisualComponent可视化组件类,用于对开店审批工作流管理系统的组件装饰作用
public class Decorator implements VisualComponent{
private VisualComponent visualComponent;
public Decorator(VisualComponent visualComponent) {
super();
this.visualComponent = visualComponent;
}
@Override
public void Operation() {
visualComponent.Operation();
}
}
4、装饰器——登记名称De_RegisterName
package com.shen.decorator;
//装饰器——登记名称De_RegisterName
public class De_RegisterName extends Decorator {
public De_RegisterName(VisualComponent visualComponent) {
super(visualComponent);
}
public void AppRegisterName() {
super.Operation();//调用基类的默认实现(调用被装饰对象的Operator方法)
System.out.println(">>>到当地工商所[登记名称]");//登记名称(添加额外工作)
}
}
5、装饰器——排污许可证De_PollutionLicense
package com.shen.decorator;
//装饰器——排污许可证De_PollutionLicense
public class De_PollutionLicense extends Decorator{
public De_PollutionLicense(VisualComponent visualComponent) {
super(visualComponent);
}
public void AppPollution() {
//super.Operation();//调用基类的默认实现(调用被装饰对象的Operator方法)
System.out.println(">>>到辖区内的环保部门申领[排污许可证]");//排污许可证(添加额外工作)
}
}
6、装饰器——卫生许可证De_Hygienic
package com.shen.decorator;
//装饰器——卫生许可证De_Hygienic
public class De_Hygienic extends Decorator{
public De_Hygienic(VisualComponent visualComponent) {
super(visualComponent);
}
public void AppHygienic() {
//super.Operation();//调用基类的默认实现(调用被装饰对象的Operator方法)
System.out.println(">>>到辖区内的卫生监督所去申领[卫生许可证]");//卫生许可证(添加额外工作)
}
}
7、装饰器——工商营业执照De_BusinessRegistration
package com.shen.decorator;
//装饰器——工商营业执照De_BusinessRegistration
public class De_BusinessRegistration extends Decorator{
public De_BusinessRegistration(VisualComponent visualComponent) {
super(visualComponent);
}
public void AppBusiness() {
//super.Operation();//调用基类的默认实现(调用被装饰对象的Operator方法)
System.out.println(">>>到工商所申请领取[工商营业执照]");//工商营业执照(添加额外工作)
}
}
8、装饰器——消防审批De_FireApproval
package com.shen.decorator;
//装饰器——消防审批De_FireApproval
public class De_FireApproval extends Decorator{
public De_FireApproval(VisualComponent visualComponent) {
super(visualComponent);
}
public void AppFire() {
//super.Operation();//调用基类的默认实现(调用被装饰对象的Operator方法)
System.out.println(">>>向消防部门申请[消防审批]");//消防审批(添加额外工作)
}
}
9、装饰器——地税税务登记号De_TaxRegistrationNumber
package com.shen.decorator;
//装饰器——地税税务登记号De_TaxRegistrationNumber
public class De_TaxRegistrationNumber extends Decorator{
public De_TaxRegistrationNumber(VisualComponent visualComponent) {
super(visualComponent);
}
public void AppTax() {
//super.Operation();//调用基类的默认实现(调用被装饰对象的Operator方法)
System.out.println(">>>向当地税务局申请领取[地税税务登记号]");//地税税务登记号(添加额外工作)
}
}
10、装饰器——药品经验许可证De_DrugBusinessLicense
package com.shen.decorator;
//装饰器——药品经验许可证De_DrugBusinessLicense
public class De_DrugBusinessLicense extends Decorator{
public De_DrugBusinessLicense(VisualComponent visualComponent) {
super(visualComponent);
}
public void AppDrug() {
//super.Operation();//调用基类的默认实现(调用被装饰对象的Operator方法)
System.out.println(">>>向当地的药监局申领[药品经营许可证]");//药品经营许可证(添加额外工作)
}
}
11、装饰器——其它额外手续De_OtherExtraProcedures
package com.shen.decorator;
//装饰器——其它额外手续De_OtherExtraProcedures
public class De_OtherExtraProcedures extends Decorator{
public De_OtherExtraProcedures(VisualComponent visualComponent) {
super(visualComponent);
}
public void AppOther() {
//super.Operation();//调用基类的默认实现(调用被装饰对象的Operator方法)
System.out.println(">>>办理其它额外手续......\n\n");//其它额外手续(添加额外工作)
}
}
(四)编写测试代码如下所示:
1、开一家小餐馆审批工作流测试代码
package com.shen.decorator;
//客户装饰器测试类
public class ClientDecoratorTest {
public static void main(String[] args) {
VisualComponent vc=new ShopApprovalProcess();//创建一个被装饰对象,公共接口的实例
Decorator dec=new Decorator(vc); //创建一个装饰器对象,用以实例化各种装饰器
/*------------以下为开一家小餐馆所需审批工作流-----------------*/
System.out.println("---------《以下为开一家小餐馆所需审批工作流》---------");
//登记名称
De_RegisterName dec1=new De_RegisterName(dec);
dec1.AppRegisterName();
//排污许可证
De_PollutionLicense dec2=new De_PollutionLicense(dec);
dec2.AppPollution();
//卫生许可证
De_Hygienic dec3=new De_Hygienic(dec);
dec3.AppHygienic();
//工商营业许可证
De_BusinessRegistration dec4=new De_BusinessRegistration(dec);
dec4.AppBusiness();
//消防审批
De_FireApproval dec5=new De_FireApproval(dec);
dec5.AppFire();
//地税税务登记号
De_TaxRegistrationNumber dec6=new De_TaxRegistrationNumber(dec);
dec6.AppTax();
//其它额外手续
De_OtherExtraProcedures dec7=new De_OtherExtraProcedures(dec);
dec7.AppOther();
}
}
调试程序,运行结果如图所示:
2、开一家药店审批工作流测试代码
package com.shen.decorator;
//客户装饰器测试类
public class ClientDecoratorTest {
public static void main(String[] args) {
VisualComponent vc=new ShopApprovalProcess();//创建一个被装饰对象,公共接口的实例
Decorator dec=new Decorator(vc); //创建一个装饰器对象,用以实例化各种装饰器
/*------------以下为开一家药店所需审批工作流-----------------*/
System.out.println("---------《以下为开一家药店所需审批工作流》---------");
//登记名称
De_RegisterName dec1=new De_RegisterName(dec);
dec1.AppRegisterName();
//卫生许可证
De_Hygienic dec2=new De_Hygienic(dec);
dec2.AppHygienic();
//工商营业许可证
De_BusinessRegistration dec3=new De_BusinessRegistration(dec);
dec3.AppBusiness();
//药品经营许可证
De_DrugBusinessLicense dec4=new De_DrugBusinessLicense(dec);
dec4.AppDrug();
//消防审批
De_FireApproval dec5=new De_FireApproval(dec);
dec5.AppFire();
//地税税务登记号
De_TaxRegistrationNumber dec6=new De_TaxRegistrationNumber(dec);
dec6.AppTax();
//其它额外手续
De_OtherExtraProcedures dec7=new De_OtherExtraProcedures(dec);
dec7.AppOther();
}
}
调试程序,运行结果如图所示:
五、实验结果和讨论
(一)开一家小餐馆程序代码运行结果如下图所示:
(二)开一家药店程序代码运行结果如下图所示:
六、总结
(一)本次实验按时按量完成。通过实验基本掌握了结构型设计模式中的装饰器模式。
(二)本次实验使用的是装饰器模式,它动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。装饰器模式在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
优点:
1. 装饰器模式与继承关系的目的都是要扩展对象的功能。但是装饰器模式比静态继承更灵活,装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。
2. 装饰器模式可以避免在层次结构高层的类有太多的特征。
3. 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。
缺点:
1. Decorator与它的Component不一样。Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰时不应该依赖对象标识。
2. 由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。
(三)使用装饰器模式的心得体会:
1.装饰器模式除了采用组合的方式取得了比采用继承方式更好的效果外,它还给设计带来一种“即用即付”的方式来添加职责。在OO设计和分析经常有这一种情况:为了多态,通过父类指针指向其具体子类,但是这就带来另外一个问题,当具体子类要添加新的职责,就必须向其父类添加一个这个职责的抽象接口,否则是通过父类指针是调用不到这个方法的。这样处于高层的父类就承载了太多的特征(方法),并且继承自这个父类的所有子类都不肯避免继承了父类的这些接口,但是可能这并不是这个具体子类所需要的。而在装饰器模式提供了一种较好的解决方法,当需要添加一个操作的时候就可以通过装饰器模式来解决,也可以一步步添加新的职责。
2.装饰器模式具有比继承更加灵活机动的特性,也同时意味着更加多的复杂性。装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
装饰模式是针对抽象组件(Component)类型编程。但是,如果要针对具体组件编程时,就应该重新思考应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
七、附加要求
对于我们所介绍的常见的几种结构型的设计模式,举出这些模式的一些应用实例,并给出相关的UML类图说明。
对适配器模式(Adapter)的举例如下:
水利工程的水管有大号、小号水管之分,而水管适配器的作用是将大号水管与小号水管连接起来,以达到大号水管的水能够流到小号水管中的作用。
(一) UML类图设计如下所示:
(二) 代码设计如下所示:
1、大号水管
package com.shen.adapter;
//大号水管
public class BigWaterPipe {
public void Common() {
System.out.println("我是大号水管");
}
}
2、小号水管
package com.shen.adapter;
//小号水管
public class SmallWaterPipe {
public void Special() {
System.out.println("我是小号水管");
}
}
3、水管适配器
package com.shen.adapter;
//水管适配器
public class WaterPipeAdapter extends BigWaterPipe {
private SmallWaterPipe swp=new SmallWaterPipe();
public void Common() {
System.out.println("我是水管适配器,使大号水管和小号水管能够连接起来。");
swp.Special();
}
}
4、适配器测试类
package com.shen.adapter;
//适配器测试类
public class AdapterTest {
public static void main(String[] args) {
System.out.println("----------105032013120----------");
BigWaterPipe bwp1=new BigWaterPipe();
bwp1.Common();
BigWaterPipe bwp2=new WaterPipeAdapter();
bwp2.Common();;
}
}
(三) 测试结果如下所示:
面向对象程序设计(OOP设计模式)-结构型模式之装饰器模式的应用与实现的更多相关文章
- Java进阶篇设计模式之五-----外观模式和装饰器模式
前言 在上一篇中我们学习了结构型模式的适配器模式和桥接模式.本篇则来学习下结构型模式的外观模式和装饰器模式. 外观模式 简介 外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这 ...
- Java设计模式之五 ----- 外观模式和装饰器模式
前言 在上一篇中我们学习了结构型模式的适配器模式和桥接模式.本篇则来学习下结构型模式的外观模式和装饰器模式. 外观模式 简介 外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这 ...
- 深入探索Java设计模式(三)之装饰器模式
装饰器模式使你可以在运行时使用类似于对象组成的技术来装饰类.这在我们希望实例化具有新职责的对象而无需对基础类进行任何代码更改的情况下尤其有用.本文是在学习完优锐课JAVA架构VIP课程—[框架源码专题 ...
- IOS设计模式之二(门面模式,装饰器模式)
本文原文请见:http://www.raywenderlich.com/46988/ios-design-patterns. 由 @krq_tiger(http://weibo.com/xmuzyq) ...
- Java设计模式(七)Decorate装饰器模式
一.场景描述 (一)问题 系统中最初使用Crystal Report(水晶报表)工具生成报表,并将报表发送给客户端查看,此时定义一CrystalReport工具类即可完成水晶报表的生成工作. 后续报表 ...
- Java设计模式之(七)——装饰器模式
1.什么是装饰器模式? Attach additional responsibilities to an object dynamically keeping the same interface.D ...
- 涉及模式之 装饰器模式详解(与IO不解的情缘)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...
- 聊聊模板方法模式,装饰器模式以及AOP
在软件系统设计的时候,我们需要把一个大的系统按照业务功能进行拆分,做到高内聚.低耦合. 但是呢,拆分之后会产生一些通用性的东西,比如日志,安全,事务,性能统计等,这些非功能性需求,横跨多个模块.最lo ...
- Decorator模式(装饰器模式)
Decorator模式? 假如现在有一块蛋糕,如果只涂上奶油,其他什么都不加,就是奶油蛋糕.如果加上草莓,就是草莓奶油蛋糕.如果再加上一块黑色巧克力板,上面用白色巧克力写上姓名,然后插上代表年龄的蜡烛 ...
随机推荐
- spring事务管理器的源码和理解
原文出处: xieyu_zy 以前说了大多的原理,今天来说下spring的事务管理器的实现过程,顺带源码干货带上. 其实这个文章唯一的就是带着看看代码,但是前提你要懂得动态代理以及字节码增强方面的知识 ...
- cubieboard 通过VGA点亮电脑屏幕笔记
前题:由于公司某些方面的需要,于是就开始尝试了来通过VGA输出--因为不可能每个地方都是高清电视,这是其一:如果要买一个HDMI转VGA的话,成本上就有所上升:反正吧,各种理由,都觉得直接通过VGA输 ...
- go语言之进阶篇方法面向过程和对象函数的区别
1.方法 (method) 在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数,这种带有接收者的函数,我们称为方法(method). 本质上,一个方法则是一个和特 ...
- ubuntu14.04上编译安装python3.7.3
首先先去python官网www.python.org下载python3.7.3的官方压缩包Python-3.7.3.tgz 一.先安装需要的包zlib1g,libffi apt-get update ...
- .Net应用程序打包部署总结
编译源代码并完成测试以后,开发过程其实并没有结束.在这个极端,需要把应用程序提供给用户.无论是ASP.NET应用程序,客户端应用程序还是 Compact Framework构建的应用程序,开发出来的软 ...
- php防止sql注入漏洞代码 && 几种常见攻击的正则表达式
注入漏洞代码和分析 ...
- ListView 控件与 内容
1)由控件获取内容:ListViewItem item = Utilities.GetVisualParent<ListViewItem>(chx); if (item == null) ...
- 【转】Understanding the Angular Boot Process
原文: https://medium.com/@coderonfleek/understanding-the-angular-boot-process-9a338b06248c ----------- ...
- 2. Using 'dp' instead of 'px' to set text size
android:textSize="45px" ==> android:textSize="45dp" 因为Android Phone的手机分辨率各不相 ...
- 【canvas】N角光阑
这回把光阑代码统一了,修改angleCount的数目为3就是三角光阑,angleCount的数目为4就是四角光阑,angleCount的数目为6就是六角光阑,目前代码中是12角光阑. 图示: 代码: ...