装饰器模式--改善代码的利器

文章通过一个程序员逐步重构代码以适应不断变化的产品需求的故事,介绍了装饰器模式的概念和重要性。程序员首先创建了各种形状的类,然后通过抽象颜色类和具体颜色类实现对形状的装饰,增强功能,提高代码的扩展性和灵活性。装饰器模式在JavaIO库中的应用也被提及,展示了其在解决功能组合和避免类爆炸问题上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题引入及优化过程

假如你是一个程序员,产品经理给你提了一个简单的需求,画一个正方形,对,就是这么简单,只需要画一个正方形.

然后你直接写了个画正方形的方法.ok 搞定.

过了两天,产品经理又加了一个小小的改变,还需要画一个长方形,你又写了个画长方形的方法,在程序中调用一下就好了,又搞定了.

又过了两天,产品经理又加了一个小改变,还需要画一个圆形,后知后觉的你发现这样下去不是办法,每次还得改程序调用,非常不利于扩展,但是又被心里的懒惰给战胜了,已经上线的代码怎么能轻易改呢?还是直接再写个方法直接调用哇.就这样,屎山代码就快要搭建完成了.

又过了两天,产品经理又找你了,需要给这些形状填充上红色,听到这个需求,你人已经麻了,那我岂不是在创建所有形状之后,再调用填充红色方法,这改动可大了,于是,痛定思痛,你决定要重构这些代码.

天资聪颖的你不一会就有了头绪,这些形状一定是有共性的,我可以定义一个接口,然后有不同的形状实现类. 那怎么都填充上红色呢?这个狗产品后期肯定又想要别的颜色,现在也不说,我得想好了,不然后期改代码又那么多.

怎么才能对不同的形状进行灵活的填充颜色呢?

哇,不愧是我,太屌了,我怎么这么聪明,我可以把这个形状接口当做一个变量传入到红色类中,那这样只需要在调用的时候传入不同的形状对象即可.

于是你激动的进行了第一次重构.以下是重构的成果.

形状接口类:

public interface Shape {
    void draw();
}

正方形实现类:

public class SquareShapeImpl implements Shape{
    @Override
    public void draw() {
        System.out.println("画出圆形");
    }
}

圆形实现类

public class CircleShapeImpl implements Shape{
    @Override
    public void draw() {
        System.out.println("画出正方形");
    }
}

红色类

public class Red {

    private Shape shape;

    public Red(Shape shape) {
        this.shape = shape;
    }

    public void draw(){
        
        shape.draw();
        System.out.println("填充红色");
    }


}

测试效果:
在这里插入图片描述

写完这些你有了一些成就感,又隐约中感觉这不是最优的方式,因为将来可能又有其他的颜色,其他的颜色将来对这些形状填充的时候,也需要传入形状接口,调用形状的实现类方法,这些都是共同点,我们应该把这些共同点提取出来.将来就不用写重复代码.

想到这里你搞了一个颜色的抽象类,在抽象类里面传入了形状接口.这样再有不同的颜色类时,只需要继承这个抽象类,填充颜色即可.

你开始了第二次重构.

颜色抽象类

public abstract class AbstractColor {
    private Shape shape;

    public AbstractColor(Shape shape) {
        this.shape = shape;
    }

    public void draw(){
        shape.draw();
        fillColor();
    }

    abstract void fillColor();
}

红色类:

public class Red extends AbstractColor {


    public Red(Shape shape) {
        super(shape);
    }

    @Override
    void fillColor() {
        System.out.println("填充红色");
    }
}

这样就可以随意进行组合了,后期扩展也非常的方便,想到这你不禁哈哈大笑了起来,我简直就是天生的架构师呀! 也就只有我能想出这么好的设计了.

后来在某一次业务逻辑中,你又发现这样一个问题,在某个地方你需要传入形状对象.去处理其他的业务逻辑
在这里插入图片描述
但是当你构造好红色正方形对象时,传不进去了,因为这个红色正方形对象和形状并没有继承关系,想到这里你赶紧去弥补了这个操作.
在这里插入图片描述
将颜色抽象类实现了形状接口,其实认真想一想,这个颜色抽象类本身就是去装饰形状类的,就应该是它的子类.

解决了这个问题后,你又不禁夸了夸自己, 天才呀…

装饰器模式介绍

其实上面这个例子最终的实现就是一个装饰器模式,就是一些大佬在不断实践中总结出来的一些好的经验.

装饰器模式包括了以下几个角色:接口、具体对象、装饰类、具体装饰类。

接口定义了具体对象的一些实现方法;具体对象定义了一些初始化操作,比如上面的案例中,画出各种形状的图案都是初始化操作;装饰类则是一个抽象类,比如上面案例中的抽象颜色类, 主要用来初始化具体对象,调用初始化方法;其它的具体装饰类都继承了该抽象类。

这里参照开头案例画一个具体的类图,看起来就清晰多了.
在这里插入图片描述

装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。这也是判断是否该用装饰器模式的一个重要的依据。除此之外,装饰器模式还有一个特点,那就是可以对原始类嵌套使用多个装饰器。为了满足这个应用场景,在设计的时候,装饰器类需要跟原始类继承相同的抽象类或者接口。

源码中的使用

装饰器模式,在哪些源码中有使用呢?

在Java语言中的最著名的应用莫过于Java I/O标准库的设计了。

由于Java I/O库需要很多功能的各种组合,如果这些功能都是用继承的方法实现的,那么每一种组合都需要一个类,就会导致组合爆炸, 类继承结构变得复杂无比。而如果采用装饰模式,那么类的数目就会大大减少,功能的重复也可以减至最少。因此装饰模式是Java I/O库的基本模式。

举例:
FilterInputStream 就对 InputStream进行了装饰.InputStream是一个抽象类,
FilterInputStream将InputStream当做一个参数传进去,从而对InputStream对象进行了装饰.增强了功能
在这里插入图片描述
在这里插入图片描述
就像我们开头样例中,AbstractColor对Shape进行了装饰一样.

有小伙伴可能会疑虑这个Java IO 中装饰者使用跟笔者提到的样例结构怎么不一样呢?到底哪个才是装饰者模式, 其实两个都是 ,两个最主要的区别就是笔者开头的样例多了一层抽象类.这个主要是为了抽公共.核心思想, 本质是不变的. 我们在使用某个设计模式也可以灵活多变,并不是把一个接口改成一个抽象类等等就不是某个设计模式了.可以根据我们实际的情况做一些改变.

今天的分享就到这里了,有问题可以在评论区留言,均会及时回复呀.
我是bling,未来不会太差,只要我们不要太懒就行, 咱们下期见.
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员bling

义父,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值