Java描述设计模式(09):装饰模式

Wesley13
• 阅读 668

本文源码:GitHub·点这里 || GitEE·点这里

一、生活场景

1、场景描述

孙悟空有七十二般变化,他的每一种变化都给他带来一种附加的本领。他变成鱼儿时,就可以到水里游泳;他变成鸟儿时,就可以在天上飞行。

2、场景图解

Java描述设计模式(09):装饰模式

3、代码实现

public class C01_InScene {
    public static void main(String[] args) {
        TheGreatestSage greatestSage = new Monkey();
        TheGreatestSage fish = new Fish(greatestSage);
        fish.shapeDesc();
        // 这里虽然是鱼形态,但是本体是悟空,所以可以直接变化
        TheGreatestSage bird = new Bird(fish);
        bird.shapeDesc();
    }
}
// 顶级接口
interface TheGreatestSage {
    // 定义一个描述形态的方法
    void shapeDesc ();
}
// 悟空本尊
class Monkey implements TheGreatestSage{
    @Override
    public void shapeDesc() {
        System.out.println("Monkey.move()");
    }
}
// 包装一层变化的描述
class Change implements TheGreatestSage {
    private TheGreatestSage greatestSage;
    Change(TheGreatestSage greatestSage){
        this.greatestSage = greatestSage;
    }
    @Override
    public void shapeDesc() {
        greatestSage.shapeDesc();
    }
}
// 具体的变化形态
class Fish extends Change{
    public Fish(TheGreatestSage greatestSage) {
        super(greatestSage);
    }
    public void shapeDesc(){
        System.out.println("鱼在水中游...");
    }
}
class Bird extends Change{
    public Bird(TheGreatestSage greatestSage) {
        super(greatestSage);
    }
    public void shapeDesc(){
        System.out.println("鸟在空中飞...");
    }
}

二、装饰模式

1、基础概念

装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。

2、核心角色

  • 抽象构件角色

给出一个抽象接口,以规范准备接收附加责任的对象。

  • 具体构件角色

定义一个将要接收附加责任的类。

  • 装饰角色

持有一个构件对象的实例,并定义一个与抽象构件接口一致的接口。

  • 具体装饰角色

负责给构件对象“贴上”附加的责任。

3、模式图解

Java描述设计模式(09):装饰模式

4、源代码实现

// 抽象构件角色
interface Component {
    void sampleOperation();
}
// 具体构件角色
class ConcreteComponent implements Component{
    @Override
    public void sampleOperation() {
        System.out.println("业务相关代码");
    }
}
//装饰角色
class Decorator implements Component{
    private Component component;
    public Decorator(Component component){
        this.component = component;
    }
    @Override
    public void sampleOperation() {
        //委派给构件进行处理
        component.sampleOperation();
    }
}
// 具体装饰角色
class ConcreteDecoratorA extends Decorator{
    public ConcreteDecoratorA(Component component) {
        super(component);
    }
    @Override
    public void sampleOperation() {
        super.sampleOperation();
        System.out.println("A.处理相关业务的代码");
    }
}
class ConcreteDecoratorB extends Decorator{
    public ConcreteDecoratorB(Component component) {
        super(component);
    }
    @Override
    public void sampleOperation() {
        super.sampleOperation();
        System.out.println("B.处理相关业务方法");
    }
}

5、该模式简化

  • 简化抽象类

如果只有一个ConcreteComponent类,那么可以考虑去掉抽象的Component类(接口),把Decorator作为一个ConcreteComponent子类。

  • 简化装饰类

如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。

6、半透明说明

1)、纯粹的装饰模式很难找到。装饰模式的用意是在不改变接口的前提下,增强类的功能。

2)、在增强功能的时候,往往需要建立新的公开的方法。

3)、这就导致了大多数的装饰模式的实现都是“半透明”的,而不是完全透明的。换言之,允许装饰模式改变接口,增加新的方法。这意味着客户端可以声明ConcreteDecorator类型的变量,从而可以调用ConcreteDecorator类中才有的方法。

4)、半透明的装饰模式是介于装饰模式和适配器模式之间的。适配器模式的用意是改变类的接口,也可以通过改写一个或几个方法,或增加新的方法来增强类的功能。

5)、大多数的装饰模式实际上是半透明的装饰模式,这样的装饰模式也称做半装饰、半适配器模式。

三、实际应用

1、JDK中IO流

1)、基本描述

装饰模式在Java语言中的最经典的应用就是Java I/O类库的设计。很少单一的创建流对象,通过创建多个叠合对象来提供所期望的IO流功能,因此装饰模式是Java I/O类库的基本模式。

2)、IO流图解描述

Java描述设计模式(09):装饰模式

  • 抽象构件角色

由InputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。

  • 具体构件角色

由FileInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口。

  • 抽象装饰角色

由FilterInputStream扮演。它实现了InputStream所规定的接口。

  • 具体装饰角色

由几个类扮演,分别是BufferedInputStream、DataInputStream以及两个不常用到的类LineNumberInputStream、PushbackInputStream。

四、优缺点总结

1、模式的优点

(1)装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。

(2)通过使用不同的具体装饰类以及这些装饰类的排列组合,工程师可以创造出很多不同行为的组合。

2、模式的优点

由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。

五、源代码地址

GitHub·地址
https://github.com/cicadasmile/model-arithmetic-parent
GitEE·地址
https://gitee.com/cicadasmile/model-arithmetic-parent

Java描述设计模式(09):装饰模式

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
Linux系统:Centos7下搭建ClickHouse列式存储数据库
本文源码:GitHub·点这里(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fcicadasmile%2Flinuxsystembase)||GitEE·点这里(https://gitee.com/cicadasmile/linuxsystem
Stella981 Stella981
3年前
SpringBoot2 整合Ehcache组件,轻量级缓存管理
本文源码:GitHub·点这里(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fcicadasmile%2Fmiddlewareparent)||GitEE·点这里(https://gitee.com/cicadasmile/middleware
Easter79 Easter79
3年前
SpringCloud微服务(07):Zipkin组件,实现请求链路追踪
本文源码:GitHub·点这里(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fcicadasmile%2Fspringcloudbase)||GitEE·点这里(https://gitee.com/cicadasmile/springcloud
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
Java并发编程(03):多线程并发访问,同步控制
本文源码:GitHub·点这里(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fcicadasmile%2Fjavabaseparent)||GitEE·点这里(https://gitee.com/cicadasmile/javabasepare
Wesley13 Wesley13
3年前
00_设计模式之语言选择
设计模式之语言选择设计模式简介背景设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式(Designpattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这