Java设计模式07:常用设计模式之装饰器模式(结构型模式)
1. Java之装饰器模式(Decorator Pattern)
(1)概述:
装饰模式在Java种使用也很广泛,比如我们在重新定义按钮、对话框等时候,实际上已经在使用装饰模式了。在不必改变原类文件和使用继承的情况下,装饰模式使用一种对客户端透明的方式来动态地扩展对象的功能,同时它也是继承关系的一种替代方案之一,它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰者模式:动态地给一个对象添加一些额外的职责,就像在墙上刷油漆一样。就增加功能来说,Decorator模式比生成子类更为灵活。
Decorator模式的工作原理是:可以创建始于Decorator对象(负责新的功能的对象)终于原对象的一个对象"链"

图1 装饰者链
装饰模式的特点:
(2)装饰模式的UML类图:

抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这些对象动态地添加职责。
具体组件角色(ConcreteComponent) :被装饰者,定义一个将要被装饰增加功能的类。可以给这个类的对象添加一些职责
抽象装饰器(Decorator):维持一个指向构件Component对象的实例,并定义一个与抽象组件角色Component接口一致的接口
具体装饰器角色(ConcreteDecorator):向组件添加职责。
(3)下面是装饰者模式通用模式代码:
/******************抽象组件类**************/
public abstract class Component {
/**
* 抽象的方法,这个随你做
* 同样第你也可以增加更多的抽象方法
*/
public abstract void operate();
} /******************组件具体实现类**************/
public class ConcreteComponent extends Component {
@Override
public void operate() {
//具体逻辑,这个随你做
}
} /******************抽象装饰者**************/
public abstract class Decorator extends Component {
private Component component;//持有一个Component对象的引用
/*
*必要的构造方法 需要一个Component类型的对象
*
* @param component Component对象
*/
public Decorator(Component component) {
this.component = component;
} @Override
public void operate() {
component.operate();
} } /******************装饰者具体实现类A**************/
public class ConcreteDecoratorA extends Decorator {
protected ConcreteDecoratorA(Component component) {
super(component);
} @Override
public void operate() {
//装饰方法A和B既可在父类方法前调用也可在之后调用
operateA(); super.operate(); operateB();
} /**
* 自定义的装饰方法A
*/
public void operateA() {
//装饰方法的逻辑
} /**
* 自定义的装饰方法B
*/
public void operateB() {
//装饰方法的逻辑
}
} /******************装饰者具体实现类B**************/
public class ConcreteDecoratorB extends Decorator { protected ConcreteDecoratorB(Component component) {
super(component);
} @Override
public void operate() {
//装饰方法A和B既可在父类方法前调用也可在之后调用
operateA(); super.operate(); operateB();
} /**
* 自定义的装饰方法A
*/
public void operateA() {
//装饰方法的逻辑
} /**
* 自定义的装饰方法B
*/
public void operateB() {
//装饰方法的逻辑
}
} /******************客户调用类**************/
public class Client {
public static void main(String[] args) {
//构建被装饰的组件对象
Component component = new Component(); //根据组件对象构建装饰者对象A并调用,此时相当于给组件对象增加装饰者A的功能方法
Decorator decorator = new ConcreteDecoratorA(component);
decorator.operate(); //根据组件对象构建装饰者对象B并调用,此时相当于给组件对象增加装饰者B的功能方法
Decorator decoratorB = new ConcreteDecoratorB(component);
decoratorB.operate();
}
}
2. 装饰器模式简单实现:
人需要各式各样的衣着,不管你穿着怎么样,但是,对于个人的本质来说是不可变的,充其量只是在外面披上一层遮羞物。
(1)人总是需要穿衣服的,我们这里将人定义一个抽象类,将穿衣的行为定义一个抽象方法:
抽象组件类:
public abstract class Person {
/**
* Person 下有一个穿着的抽象方法
*/
public abstract void dressed();
}
(2)接下来我们需要具体装饰谁呢? 也就是说我们需要创建一个具体组件类,如下:
具体组件类:
public class Boy extends Person {
@Override
public void dressed() {
//Boy 类下dressed方法的基本逻辑
System.out.println("穿了内衣内裤");
}
}
(3)上面的Boy类就是我们所要装饰的具体对象,现在需要一个装饰者来装饰我们的这个Boy对象,这里定义一个PersonCloth类来表示人所穿着的衣服
抽象装饰者类:
public abstract class PersonCloth extends Person {
protected Person mPerson;//保持一个Person类的引用
public PersonCloth(Person mPerson) {
this.mPerson = mPerson;
}
@Override
public void dressed() {
//调用Person类中的dressed方法
mPerson.dressed();
}
}
在PersonCloth类中我们保持一个对Person的引用,这样就可以方便地调用具体被装饰对象中的方法,这也是为什么我们可以在不破坏原类层次结构的情况下为类增加一些功能,我们只需要在被装饰对象的相应方法前 或者 后 增加相应的功能逻辑即可。
(4)定义两种装饰具体实现类,如下:
装饰具体实现类之 高档衣服:
public class ExpensiveCloth extends PersonCloth {
public ExpensiveCloth(Person person) {
super(person);
}
//穿短袖
private void dressShirt() {
System.out.println("穿件短袖");
}
//穿皮衣
private void dressLeather(){
System.out.println("穿件皮衣");
}
//穿牛仔裤
private void dressJean(){
System.out.println("穿牛仔裤");
}
@Override
public void dressed() {
super.dressed();
dressShirt();
dressLeather();
dressJean();
}
}
装饰具体实现类之 便宜的衣服:
public class CheapCloth extends PersonCloth {
public CheapCloth(Person mPerson) {
super(mPerson);
}
//穿短袖
private void dressShorts() {
System.out.println("穿件短袖");
}
@Override
public void dressed() {
super.dressed();
dressShorts();
}
}
(5)客户端类:
public class Main {
public static void main(String[] args) {
//首先我们要有一个Person男孩
Person person = new Boy();
//然后为他穿上便宜的衣服,比如爱哥这样的Boy
PersonCloth clothCheap = new CheapCloth(person);
clothCheap.dressed();
//或者给他穿上比较上档次的衣服,如SM
PersonCloth clothExpensive = new ExpensiveCloth(person);
clothExpensive.dressed();
}
}
Java设计模式07:常用设计模式之装饰器模式(结构型模式)的更多相关文章
- Java 23种设计模式详尽分析与实例解析之二--结构型模式
Java设计模式 结构型模式 适配器模式 模式动机:在软件开发中采用类似于电源适配器的设计和编码技巧被称为适配器模式.通常情况下,客户端可以通过目标类的接口访问它所提供的服务.又是,现有的类可以满足客 ...
- 设计模式(十二): Flyweight享元模式 -- 结构型模式
说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面 ...
- 设计模式(十):Decorator装饰者模式 -- 结构型模式
1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继 ...
- 设计模式(十三): Proxy代理模式 -- 结构型模式
设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路 ...
- 设计模式学习之路——Facade 外观模式(结构型模式)
动机: 组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战.如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系 ...
- 设计模式(八):Bridge桥接模式 -- 结构型模式
1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...
- Decorator装饰者模式(结构型模式)
1.需求 假设让我们去设计FCL中的Stream类,该类具有流类的基本功能,除了有各种不同类型的流外(如内存流.文件流.网络流等等),但是在不同的业务场景下,如处理银行业务,需要给相关的内存流进行加密 ...
- 设计模式(九):Composite组合模式 -- 结构型模式
1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对 ...
- 设计模式(十一):FACADE外观模式 -- 结构型模式
1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子1:一个电源总开关可以控制四盏灯.一个风扇 ...
- Decorator(装饰)-对象结构型模式
1.意图 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 2.别名 包装器 Wrapper. 3.动机 给某个对象而不是整个类添加一些功能.一个较为灵 ...
随机推荐
- 房租管理小软件(六):通用功能包括时间,效验,MD5加密,XML 操作
1.时间相关 public static DateTime getNow() { MyFZDataContext dataContext = MyFZDataContext.getDataContex ...
- 【译】 AWK教程指南
前面的话: 这几天写了一个程序,在同一个目录里生成了很多文件,需要统计其中部分文件的总大小,发现经常用到的ls.du等命令都无济于事,我甚至都想到了最笨的方法,写一个脚本:mkdir一个新目录,把要统 ...
- 【暑假】[深入动态规划]UVa 1380 A Scheduling Problem
UVa 1380 A Scheduling Problem 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=41557 ...
- ffmpeg常见命令
一.安装 下载ffmpeg,解压之后配置环境变量即为安装 打开dos界面,进入目标文件夹例如:E:/ cd E:\BaiduYunDownload\ffmpeg\ffmpeg_simple ...
- WEB开发总结(持续更新。。。)
近期开始搞搞web的东西,觉得有必要把遇到的问题总结一下,就在这里当做个笔记本吧. 1.用maven建立的web工程,在运行的时候,右键找不到“Run on server”菜单: 可以在命令提示行中, ...
- Google Android官方文档进程与线程(Processes and Threads)翻译
android的多线程在开发中已经有使用过了,想再系统地学习一下,找到了android的官方文档,介绍进程与线程的介绍,试着翻译一下. 原文地址:http://developer.android.co ...
- light oj 1008 - Fibsieve`s Fantabulous Birthday
1008 - Fibsieve`s Fantabulous Birthday PDF (English) Statistics Forum Time Limit: 0.5 second(s) Me ...
- iOS-关于微信支付
突然发现的一篇文章,这位博主介绍的还是挺详细的,给大家分享一下 不懂的也可以咨询我qq:564702640 1.申请接入 详见 微信支付申请接入 . 创建应用+审核通过,你将得到:APP_ID.APP ...
- VirtualBox NAT方式与主机互相通信
之前说过,桥接方式适合在统一的网络环境中使用(一样的网关和许可). 如果网络环境发生改变,那就难堪了 -- 这就是我遇到的问题,公司里每人的IP都是固定的. 解决办法,改为NAT网络地址转换模式. 但 ...
- Swift基本语法及与OC比较之二
//MARK:-----------------控制流----------------- //MARK: 1.for - in 循环 ,不用声明Value类型 //for value in 1...6 ...