装饰者模式(转)

设计模式读书笔记-----装饰者模式

我们都知道,可以使用两种方式给一个类或者对象添加行为。

一是使用继承。继承是给一个类添加行为的比较有效的途径。通过使用继承,可以使得子类在拥有自身方法的同时,还可以拥有父类的方法。但是使用继承是静态的,在编译的时候就已经决定了子类的行为,我们不便于控制增加行为的方式和时机。

二是使用关联。组合即将一个对象嵌入到另一个对象中,由另一个对象来决定是否引用该对象来扩展自己的行为。这是一种动态的方式,我们可以在应用程序中动态的控制。

与继承相比,关联关系的优势就在于不会破坏类的封装性,且具有较好的松耦合性,可以使系统更加容易维护。但是它的缺点就在于要创建比继承更多的对象。

一、基本定义

装饰者模式,动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。

<h1;">二、模式结构装饰者模式UML结构图。

Component: 抽象构件。是定义一个对象接口,可以给这些对象动态地添加职责。

ConcreteComponent:具体构件。是定义了一个具体的对象,也可以给这个对象添加一些职责。

Decorator: 抽象装饰类。是装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator存在的。

ConcreteDecorator:具体装饰类,起到给Component添加职责的功能。

三、实现装饰者模式

结构图如下:

装饰者模式提供了一个比较好的解决方案。

编码实现:

Component  Beverage.java

1 public abstract class Beverage {
2     protected String description = "Unknown Beverage";
3
4     public String getDescription() {
5         return description;
6     }
7
8     public abstract double cost();
9 }

四个组件:HouseBlend.java

 1 public class HouseBlend extends Beverage {
 2
 3     public HouseBlend(){
 4         description = "HouseBlend";
 5     }
 6
 7     @Override
 8     public double cost() {
 9         return 0.89;
10     }
11
12 }

DarkRoast.java

 1 public class DarkRoast extends Beverage {
 2     public DarkRoast(){
 3         description = "DarkRoast";
 4     }
 5     @Override
 6     public double cost() {
 7         return 1.05;
 8     }
 9
10 }

Espresso.java

 1 public class DarkRoast extends Beverage {
 2     public DarkRoast(){
 3         description = "DarkRoast";
 4     }
 5     @Override
 6     public double cost() {
 7         return 1.05;
 8     }
 9
10 }

Decat.java

 1 public class Decat extends Beverage {
 2     public Decat(){
 3         description = "Decat";
 4     }
 5
 6     @Override
 7     public double cost() {
 8         return 0.99;
 9     }
10
11 }

CondimentDecorator.java

1 public abstract class CondimentDecorator extends Beverage{
2     public abstract String getDescription();
3 }

Milk.java

 1 public class Milk extends CondimentDecorator {
 2     Beverage beverage;
 3
 4     public Milk(Beverage beverage){
 5         this.beverage = beverage;
 6     }
 7
 8     @Override
 9     public String getDescription() {
10         return beverage.getDescription() + " , Milk";
11     }
12
13     @Override
14     public double cost() {
15         return beverage.cost() + 0.3;
16     }
17 }

Mocha.java

 1 public class Mocha extends CondimentDecorator {
 2     Beverage beverage;
 3     public Mocha(Beverage beverage){
 4         this.beverage = beverage;
 5     }
 6
 7     @Override
 8     public String getDescription() {
 9         return beverage.getDescription() + " , Mocha";
10     }
11
12     @Override
13     public double cost() {
14         return beverage.cost() + 0.20;
15     }
16
17 }

Soy.java

 1 public class Soy extends CondimentDecorator{
 2     Beverage beverage;
 3     public Soy(Beverage beverage) {
 4         this.beverage = beverage;
 5     }
 6     @Override
 7     public String getDescription() {
 8         return beverage.getDescription() + " , Soy";
 9     }
10
11     @Override
12     public double cost() {
13         return beverage.cost() + 0.10;
14     }
15
16 }

Whip.java

 1 public class Whip extends CondimentDecorator {
 2     Beverage beverage;
 3     public Whip(Beverage beverage){
 4         this.beverage = beverage;
 5     }
 6     @Override
 7     public String getDescription() {
 8         return beverage.getDescription() + " , Whip";
 9     }
10
11     @Override
12     public double cost() {
13         return beverage.cost() + 0.20;
14     }
15
16 }

测试程序

 1 public class StarbuzzCoffee {
 2
 3     /**
 4      * @param args
 5      */
 6     public static void main(String[] args) {
 7         Beverage beverage = new Espresso();
 8         System.out.println(beverage.getDescription() + " $" + beverage.cost());
 9
10         Beverage beverage2 = new DarkRoast();
11         beverage2 = new Mocha(beverage2);
12         beverage2 = new Mocha(beverage2);
13         beverage2 = new Whip(beverage2);
14         System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
15     }
16
17 }

运行结果

<h1四、模式的优缺点< h1="">

1、装饰者模式可以提供比继承更多的灵活性

2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。

3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。

4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

缺点

1、会产生很多的小对象,增加了系统的复杂性

2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

五、模式的适用场景

1、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

2、需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。  当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

六、总结nbsp;                1、 组合和委托可以在运行时动态的添加新的行为,而继承是静态的,在系统编译时就已经决定了对象的行为。

2、装饰者模式意味着一群装饰者类,这些类用来包装具体组件

3、装饰者可以在被装饰者的行为前面或者后面加上自己的行为,甚至可以将被装饰者的行为整个取代掉,从而达到特定的目的。

4、可以用多个装饰者包装一个组件。

5、装饰者一般对于组件的客户是透明的,除非客户程序依赖于组件的具体类型。

6、装饰者会导致设计中出现许多的小对象,如果过度的使用,会让系统变得更加复杂。

7、装饰者和被装饰者对象有相同的超类型。

时间: 2024-10-29 10:45:52

装饰者模式(转)的相关文章

装饰者模式

* 通过使用修饰模式,可以在运行时扩充一个类的功能. * 原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数. * 装饰类实现新的功能,而在不需要用到新功能的地方,它可以直接调用原来的类中的方法. * 修饰类必须和原来的类有相同的接口. * 修饰模式是类继承的另外一种选择.类继承在编译时候增加行为,而装饰模式是在运行时增加行为. * 当某个类具有多种可组合叠加的行为或属性时,装饰者模式可以通过动态增加装饰类,以避免排列组合,减少需要类的数量. 共同的

javascript设计模式学习之——装饰者模式

一.装饰者模式定义 装饰者模式可以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象.这种为对象动态添加职责的方式就称为装饰者模式.装饰者对象和它所装饰的对象拥有一致的接口,对于用户来说是透明的. 和java等语言不同的是,java的装饰器模式是给对象动态添加职责,javascript中,给对象添加职责的能力是与生俱来的,更侧重于给函数动态添加职责. 二.java中的装饰者模式实现 package com.bobo.shejimoshi.derector; public cl

每天一段笔记-装饰者模式(Decorator pattern)

知识点 类应该对扩展开放,对修改封闭. 案例 (本故事纯属虚构) 某日早上,流年刚把新开发的游戏项目提交给经理 1 public abstract class Role 2 { 3 public virtual string RoleName { get; private set; } 4 public abstract int PhysicalAttack(); 5 } 1 class Samurai : Role 2 { 3 public override string RoleName 4

Java设计模式菜鸟系列(三)装饰者模式建模与实现

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39759199 装饰者(Decorator)模式:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更具有弹性的替代方案.对于装饰者模式,它其实是一种包装,所以我更愿意称它为一种包装.像咱们以前经常使用的Java里面的IO流就用到了装饰者模式.比如:BufferedReader br = new BufferedReader(new InputStreamReader(new Fi

JS设计模式之装饰者模式

装饰者模式概述 在不改变原对象的基础上,通过对其进行包装拓展(添加属性或者方法)使原有对象可以满足用户更复杂的需求 实际需求 在已有的代码基础上,为每个表单中的input默认输入框上边显示一行提示文案,当用户点击输入框时文案消失 原有代码: var telInput = document.getElementById('tel_input'); var telWarnText = document.getElementById('tel_warn_text'); input.onclick =

Java设计模式の装饰者模式

目录 一.问题引入 二.设计原则 三.用装饰者模式解决问题 四.装饰者模式的特点 五.装饰者模式的定义 六.装饰者模式的实现 七.java.io包内的装饰者模式 一.问题引入 咖啡店的类设计: 一个饮料基类,各种饮料类继承这个基类,并且计算各自的价钱. 饮料中需要加入各种调料,考虑在基类中加入一些布尔值变量代表是否加入各种调料,基类的cost()中的计算各种调料的价钱,子类覆盖cost(),并且在其中调用超类的cost(),加上特定饮料的价钱,计算出子类特定饮料的价钱. 缺点:类数量爆炸.基类加

【设计模式】之装饰器模式

为什么会有装饰模式? 装饰模式是为了解决继承强依赖性和出现大量子类不方便管理问题而出现的.   1. 概述 动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活. 原理:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数.装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法.修饰类必须和原来的类有相同的接口. 2. 模式中的角色 2.1 抽象构建(Component):定义一个抽象接口,用以给这些对象动态

Decorator Pattern(装饰器模式)Demo1

一个简单的装饰器模式例子,用来体现直接查询,缓存查询,和过滤敏感词汇 1 import java.sql.Connection; 2 import java.sql.PreparedStatement; 3 import java.sql.ResultSet; 4 import java.sql.SQLException; 5 import java.util.ArrayList; 6 import java.util.HashMap; 7 import java.util.List; 8 im

装饰器模式

定义:可以动态地添加修改类的功能 解析:一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法.使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性. $canvas1 = new IMooc\Canvas();$canvas1->init();$canvas1->addDecorator(new \IMooc\ColorDrawDecorator('green'));$canvas1->addDecorato

06JavaIO详解_IO流中的设计模式-装饰者模式

Io流里面的过滤流和节点流用的就是装饰者模式.整个的IO体系就是装饰模式. 这个写法就是装饰者模式.对上面的三个已经存在的类(DataOutputStream,BufferedOutputStream,FileOutputStream)进行组合,具有三种功能. 对于DataOutputStream dos=new DataOutStream(new BufferedOutputStream(new FileOutputStream("data.txt"))); 这行代码来说. OutP