装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。我们通过下面的实例来演示装饰器模式的用法。我们的实例是实现餐馆点餐点,基础食物:米饭,你可以搭配啤酒,可乐.鱼或者蔬菜.

  • 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

  • 主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

  • 何时使用:在不想增加很多子类的情况下扩展类。

  • 如何解决:将具体功能职责划分,同时继承装饰者模式。

  • 关键代码:

  • 1、Beverage(材料) 类充当抽象角色,不应该具体实现。

  • 2、修饰类引用和继承 Beverage(材料) 类,具体扩展类重写父类方法。

  • 应用实例:

    • 1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。
    • 2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。
  • 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

  • 缺点:多层装饰比较复杂。

  • 使用场景:

    • 1、扩展一个类的功能。
    • 2、动态增加功能,动态撤销。

注意事项:可代替继承。

代码示例

如上面所说,我们要实现参观点餐的需求,使用啤酒.鱼等辅助食材来装饰米饭(Rich)对象,要求这些材料具有相同的基类,那么下面我们先定义Beverage(材料类).

package com.zhoutao123.design.pattern.decorator;

/**
* 材料
*/
public abstract class Beverage { private String desc = "未知食材"; // 抽象方法,返回价钱
public abstract float getCost(); // 返回描述
public String getDesc(){
return desc;
}
}

然后我们定义米饭,米饭需要继承Beverage类

package com.zhoutao123.design.pattern.decorator;

/**
* 定义米饭
*/
public class Rice extends Beverage{ @Override
public String getDesc() {
return "米饭,";
} @Override
public float getCost() {
return 12;
}
}

定义一些其他食材.

package com.zhoutao123.design.pattern.decorator;

/**
* 定义啤酒
*/
public class Beer extends Beverage { private Beverage beverage; public Beer(Beverage beverage) {
this.beverage = beverage;
} @Override
public String getDesc() {
return beverage.getDesc()+"Beer,";
} @Override
public float getCost() {
return 0.2f + beverage.getCost();
}
}

剩下的重复性动作就不在定义了,可以仿照Beer一次实现Cola(可乐) Fish(鱼) Vegetable(蔬菜)由于这是示例,代码比较简单,就不做过多的说明了,大致可以看下UML

  • getDesc() 获取商品描述
  • getCost() 获取商品的价格

下面看一些测试代码,可以看到可以使用随意的商品修饰Rich,而不用担心耦合.基础Rich需要什么,我么就可以去装饰它.

package com.zhoutao123.design.pattern.decorator;

/**
* 测试装饰者模式
*/
public class TestDecorator { public static void main(String[] args) {
// 首先定义米饭
System.out.println("------------一个普通的晚餐订单---------------");
Beverage beverage = new Rice(); //分别用啤酒,可乐和鱼等食物装饰米饭
// 得到一份晚餐
beverage = new Beer(beverage);
beverage = new Fish(beverage);
beverage = new Cola(beverage); // 显示晚餐列表
System.out.println(beverage.getDesc());
// 显示晚餐总金额
System.out.println(beverage.getCost()); // 一位素食主义者的订单
System.out.println("------------一位素食主义者的订单---------------");
Beverage food = new Rice();
food = new Vegetables(food);
// 计算价钱和想清单
// 显示晚餐列表
System.out.println(food.getDesc());
// 显示晚餐总金额
System.out.println(food.getCost());
} }

结果如下,(float类型产生的误差请忽略):

------------一个普通的晚餐订单---------------
米饭,啤酒,红烧鱼,可乐,
13.400001
------------一位素食主义者的订单---------------
米饭,Vegetables,
12.5

设计模式系列之装饰模式(Decorator Pattern)的更多相关文章

  1. 设计模式系列之装饰模式(Decorator Pattern)——扩展系统功能

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  2. 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern)

    原文:乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) 作者:weba ...

  3. 二十四种设计模式:装饰模式(Decorator Pattern)

    装饰模式(Decorator Pattern) 介绍动态地给一个对象添加一些额外的职责.就扩展功能而言,它比生成子类方式更为灵活.示例有一个Message实体类,某个对象对它的操作有Insert()和 ...

  4. 设计模式-装饰模式(Decorator Pattern)

    装饰模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活

  5. 设计模式-09装饰模式(Decorator Pattern)

    1.模式动机 一般有两种方式可以实现给一个类或对象增加行为: 继承机制:使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法.但是这种方法是 ...

  6. 浅谈设计模式--装饰者模式(Decorator Pattern)

    挖了设计模式这个坑,得继续填上.继续设计模式之路.这次讨论的模式,是 装饰者模式(Decorator Pattern) 装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对 ...

  7. 装饰模式(Decorator pattern)

    装饰模式(Decorator pattern): 又名包装模式(Wrapper pattern), 它以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式以对客户透明的方式动态的给 ...

  8. 设计模式系列之适配器模式(Adapter Pattern)——不兼容结构的协调

    模式概述 模式定义 模式结构图 模式伪代码 类适配器,双向适配器,缺省适配器 类适配器 双向适配器 缺省适配器 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 主要优点 主要缺点 适 ...

  9. 设计模式系列之单例模式(Singleton Pattern)——确保对象的唯一性

    模式概述 模式定义 模式结构图 饿汉式单例与懒汉式单例 饿汉式单例 懒汉式单例 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 主要优点 适用场景 说明:设计模式系列文章是读刘伟所著 ...

随机推荐

  1. win10安装gitLab

    从控制面板选择hyper-V进行安装 1.打开控制面板选择程序=>选择启用或关闭windows功能=>选择Hyper-v 安装ubuntu 1.下载ubuntu系统(本次安装为18.04. ...

  2. ubuntu中使用docker部署.netcore2.1

     概述    .netcore发布这么久,到现在才在项目中实际运用,之前算是了解一点,一般找工作都会问是否运用过.netcore,软件研发来说,如果这个技术没用过,觉得挺难,其实不难..netcore ...

  3. 1.JAVA-Hello World

    1.Java开发介绍 J2SE:Java 2 Platform Standard Edition(2005年之后更名为JAVA SE). 包含构成Java语言核心的类.比如:数据库连接.接口定义.数据 ...

  4. 21 , CSS 构造模型

    1. div 2. 边距 3. 边框 4. 定位 5. 浮动 1 21.1  div 部分(division)---<div>元素,经常以 div 形式引用---是 XHTML 元素,用于 ...

  5. sql server2005安装时报 ‘服务无法启动’

    SQL server服务无法启动的原因分析: 在安装SQL 2005标准版(不多于四个CPU)和企业版(无限制)时,CPU的总核数必须是2的n次方.即核心数为1,2,4,8,16,32依次类推.因BL ...

  6. 今年开搞了,搭建一下vue开发环境

    首先-->搞了几天的SpringBoot玩的差不多了,领导直接说, 别项目组需要做前后端分离,说前端缺少人手,没有办法咯,只能硬着头皮去了, 说先学一下'vue',给我个文档让我学学,说是前半年 ...

  7. Luogu P5292 [HNOI2019]校园旅行

    非常妙的一道思博题啊,不愧是myy出的题 首先我们考虑一个暴力DP,直接开一个数组\(f_{i,j}\)表示\(i\to j\)的路径能否构成回文串 考虑直接拿一个队列来转移,队列里存的都是\(f_{ ...

  8. oracle 简单备注

    1. 建立数据库 备注: 1) oracle 不同于mysql 可以直接create database 2) oracle 创建schema时对应一个用户,即该schema的访问用户,与用户一一对应: ...

  9. 入门PHP你需要了解些什么?

    1.[PHP]PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,利于学习,使用广泛 ...

  10. python爬虫数据解析之xpath

    xpath是一门在xml文档中查找信息的语言.xpath可以用来在xml文档中对元素和属性进行遍历. 在xpath中,有7中类型的节点,元素,属性,文本,命名空间,处理指令,注释及根节点. 节点 首先 ...