别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(1)

简介: 别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(1)

背景

你还在写满屏的爆炸类吗?


就是不管三七二十一,把所有代码写在一个类里面,这样代码不优雅不说,如果改动涉及到老代码,可能还会影响线上的系统稳定性。


其实,很多情况,我们巧妙地利用设计模式就能解决很多潜在的系统问题,今天栈长就教大家使用装饰器模式,在不改动老代码的前提下扩展功能,不但能提升代码优雅性,还能不影响现有的功能,谁用谁知道,真香!!


什么是装饰器模式?

装饰器模式,从字面上理解,顾名思义,就是一种装饰模式,它可以在不改动原有代码的情况下,对现有的对象、行为进行新的层次的包装、装饰,增强原有的基本功能以提供更丰富的能力。


举个简单的装修的小例子:

清理 > 刮腻子 > 涂油漆 > 挂壁画


也可以是:

清理 > 刮腻子 > 贴大理石 > 挂电视


或者可以是:

清理 > 刮腻子 > 贴墙纸


这是一步步的简单装修墙面过程(哈哈,大概如此,我不是专业的),这就是装饰器模式,装饰的每个步骤互不干涉,但后面的步骤需要依赖前一个步骤的完成,后面的步骤可以不断在前一个的装饰基础上进行增加。


装饰器模式结构图如下:

image.png


装饰器模式类结构如下:


Component:组件接口类,定义被装饰类的基本功能


ConcreteComponent:组件接口的基本实现类


Decorator:装饰器角色类, 实现并持有一个 Component 对象实例


ConcreteDecorator:装饰器的实现类


装饰器模式的优点:


1、不改动原有代码,动态增加功能;


2、对象之间不会相互依赖,松耦合,够优雅;


3、符合开闭原则,扩展性好、便于维护;


装饰器模式的缺点:


1、装饰环节如果很多的话,会造成装饰器类膨胀;


2、装饰器层层嵌套比较复杂,使用者必须清楚所有的装饰器类及其用途;


装饰器模式实战

我们把上面的装修的案例用装饰器模式实现一下。


组件接口类:

/**
 * 墙面装修接口
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
public interface WallBeautify {
    /**
     * 装修操作
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    void operation();
}

组件接口的基本实现类:

/**
 * 墙面装修基本实现(清理墙面)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
public class WallBeautifyClean implements WallBeautify {
    @Override
    public void operation() {
        System.out.println("开始清理墙面");
    }
}


装饰器角色类:

这是一个抽象类,实现并持有一个 Component 对象实例,这里使用的是聚合,而不是继承,这也是装饰器模式的要点所在。

/**
 * 墙面装修装饰器角色
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
public abstract class WallBeautifyDecorator implements WallBeautify {
    /**
     * 持有一个 Component 对象实例
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    private WallBeautify wallBeautify;
    public WallBeautifyDecorator(WallBeautify wallBeautify) {
        this.wallBeautify = wallBeautify;
    }
    @Override
    public void operation() {
        wallBeautify.operation();
        decoration();
    }
    /**
     * 装饰器实现类自定义实现方法
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public abstract void decoration();
}

覆写原操作方法,在原操作之后再进行装饰,所以需要提供一个抽象的 decoration 方法供不同的装饰器的实现类去实现。


装饰器的实现类:

这里定义了 3 个装修过程:

刮腻子 > 涂油漆 > 挂壁画

所以各自去继承 装饰器角色类 并实现其装饰方法:

/**
 * 墙面装修装饰器角色实现(刮腻子)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
public class WallBeautifyPutty extends WallBeautifyDecorator {
    public WallBeautifyPutty(WallBeautify wallBeautify) {
        super(wallBeautify);
    }
    @Override
    public void decoration() {
        System.out.println("开始刮腻子");
    }
}
/**
 * 墙面装修装饰器角色实现(涂油漆)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
public class WallBeautifyPaint extends WallBeautifyDecorator {
    public WallBeautifyPaint(WallBeautify wallBeautify) {
        super(wallBeautify);
    }
    @Override
    public void decoration() {
        System.out.println("开始涂油漆");
    }
}
/**
 * 墙面装修装饰器角色实现(挂壁画)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
public class WallBeautifyHang extends WallBeautifyDecorator {
    public WallBeautifyHang(WallBeautify wallBeautify) {
        super(wallBeautify);
    }
    @Override
    public void decoration() {
        System.out.println("开始挂壁画");
    }
}

测试一下:

/**
 * 装饰器模式测试类
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
public class DecoratorTest {
    public static void main(String[] args) {
        // 清理墙面
        WallBeautify wallBeautifyClean = new WallBeautifyClean();
        wallBeautifyClean.operation();
        System.out.println("--------------");
        // 刮腻子
        WallBeautify wallBeautifyPutty = new WallBeautifyPutty(wallBeautifyClean);
        wallBeautifyPutty.operation();
        System.out.println("--------------");
        // 涂油漆
        WallBeautify wallBeautifyPaint = new WallBeautifyPaint(wallBeautifyPutty);
        wallBeautifyPaint.operation();
        System.out.println("--------------");
        // 挂壁画
        WallBeautify wallBeautifyHang = new WallBeautifyHang(wallBeautifyPaint);
        wallBeautifyHang.operation();
        System.out.println("--------------");
        // 多层嵌套
        WallBeautify wbh = new WallBeautifyHang(new WallBeautifyPaint(
                new WallBeautifyPutty(new WallBeautifyClean())));
        wbh.operation();
        System.out.println("--------------");
    }
}

本节教程所有实战源码已上传到这个仓库:

https://github.com/javastacks/javastack

输出结果:

开始清理墙面
--------------
开始清理墙面
开始刮腻子
--------------
开始清理墙面
开始刮腻子
开始涂油漆
--------------
开始清理墙面
开始刮腻子
开始涂油漆
开始挂壁画
--------------
开始清理墙面
开始刮腻子
开始涂油漆
开始挂壁画
--------------

结果输出正常!

可以看到,装饰器模式的使用还是相对比较简单的,使用装饰器模式可以达到不同的装饰效果,这样即满足了不同客户的需求,而又不用改动原有的代码,还是挺香的。

相关文章
|
3月前
|
Java C++ 开发者
"深度剖析!接口VS抽象类、聚合VS组合...这6大OOP谜题,你真的全解开了吗?点击揭秘真相!"
【8月更文挑战第19天】接口与聚合是面向对象编程的关键,对于构建灵活、可扩展的软件系统至关重要。本文澄清六个常见疑惑:接口与抽象类的区别、为何使用接口、聚合与组合的不同、接口的新特性、聚合与继承的关系,以及如何合理选择接口、聚合和继承,助你深刻理解并准确应用这些核心概念。
34 0
|
5月前
|
设计模式 uml UED
乱用继承导致的类爆炸
摘要(Markdown格式): 了解**复杂度守恒定律**,源于1984年,指出应用的复杂性无法消除,只能转移。在探究设计模式时,发现了**桥接模式**。桥接模式通过组合而非继承处理多维度变化,避免类爆炸问题。当图形颜色和类型变化时,原本的抽象类和实现类会导致大量类产生。通过桥接模式优化,将颜色和形状解耦,实现了更灵活的结构。
|
安全 Java 编译器
看个电影就能学会类的加载过程?我不信!
看个电影就能学会类的加载过程?我不信!
77 0
|
设计模式 SQL Java
有点狠有点猛,我用责任链模式重构了业务代码
文章开篇,抛出一个老生常谈的问题,学习设计模式有什么作用? 设计模式主要是为了应对代码的复杂性,让其满足开闭原则,提高代码的扩展性 另外,学习的设计模式 一定要在业务代码中落实,只有理论没有真正实施,是无法真正掌握并且灵活运用设计模式的 这篇文章主要说 责任链设计模式,认识此模式是在读 Mybatis 源码时, Interceptor 拦截器主要使用的就是责任链,当时读过后就留下了很深的印象(内心 OS:还能这样玩)
|
Java 程序员 开发者
只用一行代码,你能玩出什么花样?
只用一行代码,你能玩出什么花样?
95 1
|
设计模式 安全 Java
别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(2)
别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(2)
139 0
别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!(2)
|
Python
又烧脑又炫技还没什么用,在代码里面打印自身
又烧脑又炫技还没什么用,在代码里面打印自身
204 0
又烧脑又炫技还没什么用,在代码里面打印自身
程序人生 - 变脸的原理
程序人生 - 变脸的原理
836 0
程序人生 - 变脸的原理
|
vr&ar 图形学 索引
【Unity3D 灵巧小知识点】 ☀️ | 获取某个游戏对象下的所有子物体
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。 包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。 Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。
【Unity3D 灵巧小知识点】 ☀️ | 获取某个游戏对象下的所有子物体