JAVA设计模式--装饰器模式
JAVA设计模式--装饰器模式
装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
我们通过下面的实例来演示装饰器模式的用法。其中,我们将把一个形状装饰上不同的颜色,同时又不改变形状类。
介绍
意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
如何解决:将具体功能职责划分,同时继承装饰者模式。
关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。
应用实例: 1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。 2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。
使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。
注意事项:可代替继承。
实现
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。
RedShapeDecorator 是实现了 ShapeDecorator 的实体类。
DecoratorPatternDemo,我们的演示类使用 RedShapeDecorator 来装饰 Shape 对象。

步骤 1
创建一个接口。
Shape.java
public interface Shape {
void draw();
}
步骤 2
创建实现接口的实体类。
Rectangle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
Circle.java
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
步骤 3
创建实现了 Shape 接口的抽象装饰类。
ShapeDecorator.java
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
步骤 4
创建扩展了 ShapeDecorator 类的实体装饰类。
RedShapeDecorator.java
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
步骤 5
使用 RedShapeDecorator 来装饰 Shape 对象。
DecoratorPatternDemo.java
public class DecoratorPatternDemo {
public static void main(String[] args) {
Shape circle = new Circle();
Shape redCircle = new RedShapeDecorator(new Circle());
Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();
System.out.println("\nCircle of red border");
redCircle.draw();
System.out.println("\nRectangle of red border");
redRectangle.draw();
}
}
步骤 6
验证输出。
Circle with normal border
Shape: Circle Circle of red border
Shape: Circle
Border Color: Red Rectangle of red border
Shape: Rectangle
Border Color: Red
笔记列表
一个更易理解的实例:
装饰模式为已有类动态附加额外的功能就像LOL、王者荣耀等类Dota游戏中,英雄升级一样。每次英雄升级都会附加一个额外技能点学习技能。具体的英雄就是ConcreteComponent,技能栏就是装饰器Decorator,每个技能就是ConcreteDecorator;
//Component 英雄接口
public interface Hero {
//学习技能
void learnSkills();
}
//ConcreteComponent 具体英雄盲僧
public class BlindMonk implements Hero { private String name; public BlindMonk(String name) {
this.name = name;
} @Override
public void learnSkills() {
System.out.println(name + "学习了以上技能!");
}
}
//Decorator 技能栏
public class Skills implements Hero{ //持有一个英雄对象接口
private Hero hero; public Skills(Hero hero) {
this.hero = hero;
} @Override
public void learnSkills() {
if(hero != null)
hero.learnSkills();
}
}
//ConreteDecorator 技能:Q
public class Skill_Q extends Skills{ private String skillName; public Skill_Q(Hero hero,String skillName) {
super(hero);
this.skillName = skillName;
} @Override
public void learnSkills() {
System.out.println("学习了技能Q:" +skillName);
super.learnSkills();
}
}
//ConreteDecorator 技能:W
public class Skill_W extends Skills{ private String skillName; public Skill_W(Hero hero,String skillName) {
super(hero);
this.skillName = skillName;
} @Override
public void learnSkills() {
System.out.println("学习了技能W:" + skillName);
super.learnSkills();
}
}
//ConreteDecorator 技能:E
public class Skill_E extends Skills{ private String skillName; public Skill_E(Hero hero,String skillName) {
super(hero);
this.skillName = skillName;
} @Override
public void learnSkills() {
System.out.println("学习了技能E:"+skillName);
super.learnSkills();
}
}
//ConreteDecorator 技能:R
public class Skill_R extends Skills{ private String skillName; public Skill_R(Hero hero,String skillName) {
super(hero);
this.skillName = skillName;
} @Override
public void learnSkills() {
System.out.println("学习了技能R:" +skillName );
super.learnSkills();
}
}
//客户端:召唤师
public class Player {
public static void main(String[] args) {
//选择英雄
Hero hero = new BlindMonk("李青"); Skills skills = new Skills(hero);
Skills r =newSkill_R(skills,"猛龙摆尾");Skills e =newSkill_E(r,"天雷破/摧筋断骨");Skills w =newSkill_W(e,"金钟罩/铁布衫");Skills q =newSkill_Q(w,"天音波/回音击");//学习技能
q.learnSkills();}}输出:
学习了技能Q:天音波/回音击
学习了技能W:金钟罩/铁布衫
学习了技能E:天雷破/摧筋断骨
学习了技能R:猛龙摆尾
李青学习了以上技能!
JAVA设计模式--装饰器模式的更多相关文章
- Java设计模式--装饰器模式到Java IO 流
装饰器模式 抽象构件角色:给出一个抽象接口,以规范准备接受附加责任的对象. 具体构件角色:定义准备接受附加责任的对象. 抽象装饰角色:持有一个构件对象的实例,并对应一个与抽象构件接口一致的接口. 具体 ...
- 从源码角度理解Java设计模式——装饰者模式
一.饰器者模式介绍 装饰者模式定义:在不改变原有对象的基础上附加功能,相比生成子类更灵活. 适用场景:动态的给一个对象添加或者撤销功能. 优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个 ...
- 【设计模式】Java设计模式 - 装饰者模式
Java设计模式 - 装饰者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自 ...
- Java设计模式——装饰者模式
JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...
- 设计模式-装饰器模式(Decrator Model)
文 / vincentzh 原文连接:http://www.cnblogs.com/vincentzh/p/6057666.html 目录 1.概述 2.目的 3.结构组成 4.实现 5.总结 1.概 ...
- C#设计模式--装饰器模式
0.C#设计模式-简单工厂模式 1.C#设计模式--工厂方法模式 2.C#设计模式--抽象工厂模式 3.C#设计模式--单例模式 4.C#设计模式--建造者模式 5.C#设计模式--原型模式 6.C# ...
- 从ES6重新认识JavaScript设计模式: 装饰器模式
1 什么是装饰器模式 向一个现有的对象添加新的功能,同时又不改变其结构的设计模式被称为装饰器模式(Decorator Pattern),它是作为现有的类的一个包装(Wrapper). 可以将装饰器理解 ...
- C#设计模式-装饰器模式(Decorator Pattern)
引言 当我们完成一个软件产品开发后就需要对其进行各种测试,适配快速迭代下质量的保障.当有一个完善的产品的对象后,如果我们想要给他添加一个测试功能,那么我们可以用一个新的类去装饰它来实现对原有对象职责的 ...
- php设计模式 装饰器模式
装饰器模式,可以动态地添加修改类的功能. 一个类提供了一项功能,如果要修改并添加额外的功能,传统的编程模式需要写一个子类继承它,并重新实现类的方法.使用装饰器模式,仅需要在运行时添加一个装饰器对象即可 ...
随机推荐
- 一个web应用的诞生(1)--初识flask
基于flask的web应用的诞生 Flask是一个非常优秀的web框架,它最大的特点就是保持一个简单而易于扩展的小核心,其他的都有用户自己掌握,并且方便替换,甚至,你可以在社区看到众多开源的,可直接用 ...
- HTML5-svg圆形饼状图进度条实现原理
<svg width="440" height="440" viewbox="0 0 440 440"> <circle ...
- 基于JDK1.8的ConcurrentHashMap分析
之前看过ConcurrentHashMap的分析,感觉也了解的七七八八了.但昨晚接到了面试,让我把所知道的ConcurrentHashMap全部说出来. 然后我结结巴巴,然后应该毫无意外的话就G了,今 ...
- windows系统下安装node
最近项目中需要使用到vue框架来实现前后端分离,于是抽时间看了下vue的相关只是,从官网了解到可以使用命令行工具(CLI)来构建应用,于是在本地环境预练了一下 下面这句话摘抄自vue文档: Vue.j ...
- org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file [/Users/lonecloud/tomcat/apache-tomcat-7.0.70 2/webapps/myproject/WEB-INF/classes/cn/lone
解决这个报错的解决办法: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidat ...
- 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题
layout: post title: 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题 key: 20180303 tags: GIT 版本管理 modify_date: 2 ...
- OSQA的配置
1.安装Python,我安装的是python 2.7.3 2.安装setuptools 下载setuptools,并安装 安装好以后,在pyton2.7/scripts的路径下将会有easy_inst ...
- 为什么使用正则test( )第一次是 true,第二次是false?
今天朋友问我一个问题,我现在需要多次匹配同一个内容,但是为什么我第一次匹配,直接是 true,而第二次匹配确实 false 呢? var s1 = "MRLP"; var s2 = ...
- 从零开始学习前端JAVASCRIPT — 12、JavaScript面向对象编程
一.构造函数的使用 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- C# 带偏移量自定义分页方法
/// <summary> /// 带偏移量自定义分页方法 /// </summary> /// <param name="PageSize"> ...