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. EF Code First 学习笔记:表映射

    多个实体映射到一张表 Code First允许将多个实体映射到同一张表上,实体必须遵循如下规则: 实体必须是一对一关系 实体必须共享一个公共键 观察下面两个实体: public class Perso ...

  2. Cookie帮助类

    using System; using System.Collections.Generic; using System.Text; using System.Web; namespace AIMSC ...

  3. e2e 自动化集成测试 架构 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step (三) SqlServer数据库的访问

    上一篇文章“e2e 自动化集成测试 架构 京东 商品搜索 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step 二 图片验证码的识别” ...

  4. phpMyAdmin导入本地数据库

    phpMyAdmin导入本地数据库 在PHPMyAdmin导入数据时,点击导入--执行后出现错误: 您可能正在上传很大的文件,请参考文档来寻找解决方法. 可能就是因为数据库太大的原因. 那么如何 才能 ...

  5. eclipse下使用tomcat启动maven项目

    最近学习使用maven,建立了一个maven项目使用eclipse下tomcat启动时报错: 严重: ContainerBase.addChild: start: org.apache.catalin ...

  6. -lrt

    在编写pthread有关的程序时,编译时老是报"undefined reference to `pthread_create'"的错误,原因是没有链接pthread相关的库,gcc ...

  7. FreeModbus Slave 改进的eMbPoll()【worldsing 笔记】

    eMbPoll()的作用是FreeMod协议通信过程中不断查询事件对列有无完速数据桢,并进行地址和CRD验证,最后运行和回复主机. 为了减小代码尺寸对eMbPoll进行改进: 原版: 1:  2: e ...

  8. Resharp非常实用的快捷键

    Alt+Home  定位到父类.父接口 Alt + End 定位到子类 Ctrl+T     快速在整个解决方案下搜索 类型.方法.文件夹 Alt+Ctrl+Spance  给出提示框 Shift+F ...

  9. SpringMVC(二)

    今天在完成的工作的前提下,最终在睡觉前将SpringMVC和Mybatis整合了~~~ 其实就是按照从网上(参考http://www.toutiao.com/a6332703083554324737/ ...

  10. MSSQLSERVER数据库- LEFT JOIN后面跟着WHERE竟变成内联 解决方法

    在LEFT JOIN后面跟着WHERE竟变成内联.百度后看到这个解决方法. 记录如下: select sre.*, co.description from subscribedratingelemen ...