大聪明教你学Java设计模式 | 第七篇:装饰器模式

17,871 阅读5分钟

前言

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

🍊作者简介: 不肯过江东丶,一个来自二线城市的程序员,致力于用“猥琐”办法解决繁琐问题,让复杂的问题变得通俗易懂。

🍊支持作者: 点赞👍、关注💖、留言💌~

大聪明在写代码的过程中发现设计模式的影子是无处不在,设计模式也是软件开发人员在软件开发过程中面临的一般问题的解决方案。大聪明本着“独乐乐不如众乐乐”的宗旨与大家分享一下设计模式的学习心得。

装饰器模式

🍓🍓什么是装饰器模式🍓🍓

还是老规矩,在讲装饰器模式之前,我们先看看它的定义👇

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

说白了就是,装饰器模式可以动态地给对象添加一些额外的特征或者行为。可能有小伙伴产生疑问了:我们为什么要用到装饰器模式呢?直接生成子类不好吗?我们接着往下看...

🍓🍓为什么要使用装饰器模式🍓🍓

一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀,也就是需要实现的子类越来越多,那么肯定会有大量的代码冗余,不仅开发人员看着头疼,后期的维护人员估计也会崩溃。所以,在某些情况下就不能用继承的方式去实现扩展了,而是要请装饰器模式出马了~

装饰器模式相比于生成子类(也就是继承)更为灵活。咱们举个例子来深入理解一下:孙悟空会七十二变,可以变成人、变成动物、变成房子等等(孙悟空就是我们需要扩展的类),比如孙悟空变成了一个人,那么他在变身后就拥有了人的一些特征和行为,虽然他变成人了,但是他本质上还是一只猴子。如果采用继承的方式去实现孙悟空的七十二变,我们就得实现七十二个子类,很显然这个是不现实的,所以我们就需要用装饰器模式来帮助我们实现类的扩展了。

我们可以在以下几种场景中考虑使用装饰器模式👇

  • 在不影响其它对象的情况下,以动态、透明的方式给单个对象添加新的行为或特征
  • 处理可以撤销的行为或特征(即行为或特征是临时属性)
  • 当使用子类扩展的方式不切实际的时候,可考虑使用装饰器模式

个人猜测:英雄联盟(LOL)中可能就用到了装饰器模式来实现各个英雄的行为和特征,每个英雄都有一些共同点(比如所有英雄都拥有血量、都拥有等级...)和不同点(各个英雄的技能不同、外形及动作不同...),如果通过继承的方式去实现各个英雄的特征有点不切实际(毕竟有一百多个英雄呢,总不会去继承一百多个子类吧🤭),所以猜测 LOL 的开发者们使用的是装饰器模式。

🍓🍓实现装饰器模式🍓🍓

上面说了那么多概念性的东西,接下来我们就用代码去实现一下👇

🥝抽象组件类 & 具体组件类🥝

/**
 * 抽象组件类
 * @description: Component
 * @author: 庄霸.liziye
 * @create: 2022-04-06 11:29
 **/
abstract class Component {
    public abstract void operation();
}

/**
 * 具体组件类
 * @description: ConcreteComponent
 * @author: 庄霸.liziye
 * @create: 2022-04-06 11:30
 **/
class ConcreteComponent extends Component {
    @Override
    public void operation(){
        System.out.println("hello, my name is ConcreteComponent");
    }
}

🥝抽象装饰器类 & 具体装饰器类🥝

/**
 * 抽象装饰器类
 * @description: Decorator
 * @author: 庄霸.liziye
 * @create: 2022-04-06 14:34
 **/
abstract class Decorator extends Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }
    @Override
    public void operation(){
        component.operation();
    }
}

/**
 * 具体装饰器类
 * @description: Decorator
 * @author: 庄霸.liziye
 * @create: 2022-04-06 14:35
 **/
class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component){
        super(component);
    }
    private void operationFirst(){
        System.out.println("hello, my name is operationFirst");
    }
    private void operationLast(){
        System.out.println("hello, my name is operationLast");
    }
    @Override
    public void operation() {
        operationFirst();
        super.operation();
        operationLast();
        anotherOperation();
    }
    //新功能
    public void anotherOperation() {
        System.out.println("hello, my name is  anotherOperation");
    }
}

🥝测试🥝

public static void main(String[] args){
    Component component = new ConcreteComponent ();
    Decorator decorator = new ConcreteDecorator(component);
    decorator .operation();
    System.out.println("----------------我是分割线-----------------");
    Decorator decoratorBand = new ConcreteDecorator(decorator);
    decoratorBand.operation();
}

🥝运行结果🥝 在这里插入图片描述 通过上面的代码我们可以看出,装饰器模式共由四部分组成👇

  1. 抽象组件角色(Component): 定义可以动态添加任务的对象的接口
  2. 具体组件角色(ConcreteComponent):定义一个要被装饰器装饰的对象,即 Component 的具体实现
  3. 抽象装饰器(Decorator): 维护对象和其子类的引用
  4. 具体装饰器角色(ConcreteDecorator):向对象添加新的功能或行为特征

🍓🍓装饰器模式的优缺点🍓🍓

最后我们总结一下装饰器模式的优缺点👇

🍌🍌优点🍌🍌

装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

🍌🍌缺点🍌🍌

如果涉及到多层装饰的话,整体代码结构就会比较复杂。

小结

本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨🙇‍

希望各位小伙伴动动自己可爱的小手,来一波点赞+关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●'◡'●)

如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。

你在被打击时,记起你的珍贵,抵抗恶意; 你在迷茫时,坚信你的珍贵,抛开蜚语; 爱你所爱 行你所行 听从你心 无问东西