1. Java之装饰器模式(Decorator Pattern)

(1)概述:

    装饰模式在Java种使用也很广泛,比如我们在重新定义按钮、对话框等时候,实际上已经在使用装饰模式了。在不必改变原类文件和使用继承的情况下,装饰模式使用一种对客户端透明的方式来动态地扩展对象的功能,同时它也是继承关系的一种替代方案之一,它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

    装饰者模式:动态地给一个对象添加一些额外的职责,就像在墙上刷油漆一样。就增加功能来说,Decorator模式比生成子类更为灵活。

  Decorator模式的工作原理是:可以创建始于Decorator对象(负责新的功能的对象)终于原对象的一个对象"链"

                       

                        图1  装饰者链

装饰模式的特点:

  • 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
  • 装饰对象包含一个真实对象的引用(reference)
  • 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
  • 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

 

(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:常用设计模式之装饰器模式(结构型模式)的更多相关文章

  1. Java 23种设计模式详尽分析与实例解析之二--结构型模式

    Java设计模式 结构型模式 适配器模式 模式动机:在软件开发中采用类似于电源适配器的设计和编码技巧被称为适配器模式.通常情况下,客户端可以通过目标类的接口访问它所提供的服务.又是,现有的类可以满足客 ...

  2. 设计模式(十二): Flyweight享元模式 -- 结构型模式

    说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面 ...

  3. 设计模式(十):Decorator装饰者模式 -- 结构型模式

    1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继 ...

  4. 设计模式(十三): Proxy代理模式 -- 结构型模式

      设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路 ...

  5. 设计模式学习之路——Facade 外观模式(结构型模式)

    动机: 组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战.如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系 ...

  6. 设计模式(八):Bridge桥接模式 -- 结构型模式

    1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...

  7. Decorator装饰者模式(结构型模式)

    1.需求 假设让我们去设计FCL中的Stream类,该类具有流类的基本功能,除了有各种不同类型的流外(如内存流.文件流.网络流等等),但是在不同的业务场景下,如处理银行业务,需要给相关的内存流进行加密 ...

  8. 设计模式(九):Composite组合模式 -- 结构型模式

    1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对 ...

  9. 设计模式(十一):FACADE外观模式 -- 结构型模式

    1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子1:一个电源总开关可以控制四盏灯.一个风扇 ...

  10. Decorator(装饰)-对象结构型模式

    1.意图 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 2.别名 包装器 Wrapper. 3.动机 给某个对象而不是整个类添加一些功能.一个较为灵 ...

随机推荐

  1. 从Decorator,Adapter模式看Java的IO库

    我想任何一本介绍模式的书在讲到Decorator模式的时候不能不提到它的实际应用--在Java/IO库里面的应用,<<Java与模式>>这本书也不例外,有点不一样的是,这本书在 ...

  2. double free or corruption的原因

    问题描述: 使用hiredisCluster 运行报错,错误截图如下: 通过分析hiredis源代码发现,在net.c的源文件中283行代码: c->tcp.host = strdup(addr ...

  3. HOG:从理论到OpenCV实践

    (转载请注明出处:http://blog.csdn.net/zhazhiqiang/ 未经允许请勿用于商业用途) 一.理论 1.HOG特征描述子的定义:     locally normalised ...

  4. flash player 版本对照

  5. #ifdef _cplusplus (转)

    原文不可考,转载链接:http://blog.csdn.net/owldestiny/article/details/5772916 有发现原文的请告知,我会及时更新. 时常在cpp的代码之中看到这样 ...

  6. 深入浅出 JavaScript 变量、作用域和内存 v 0.5

    本文主要从原理入手分享变量和作用域的相关知识,最后结合本文所分享知识,再次深入了解下闭包的运行原理. 主要参考<JS高级程序设计> <JS权威指南> <高性能 JS> ...

  7. hive 中出现struct 结构化的问题

    如果你使用udf,udaf,udtf中的某一个并且查询日志中出现如下之类的struct错误 java.lang.RuntimeException: Error in configuring objec ...

  8. 我用的Linux命令

    从今天起,会在这里记一些我使用过的linux命令 =======I'm 分割线======= 11.查看某个端口号被哪个应用占用 netstat -apn|grep 端口号,lsof -i:端口号,n ...

  9. oracle 修改用户下部分表现有表空间

    工作日记之<修改用户表现有表空间> //user_tables可查询出当前登录用户的所有表,以及部分表信息,可以灵活运用于其他用途 //假设现有表空间TS1.TS2,需要迁移所有表空间TS ...

  10. mybatis-generator-core自动生成do、mapping、dao 代码

    使用mybatis配置映射文件,有点麻烦,容易出错,可以使用jar工具自动生成代码,即高效又方便 一.下载两个jar,并放置在G:\tool\maven\generator目录下(自己定义) myba ...