装饰器模式:藏在漫威电影里的设计模式

你或许不熟悉装饰器模式,但是漫威电影系列你肯定并不陌生,在电影播出之后,或许你听过这样的声音:

一个紫色番薯,打了一个响指,众多超级英雄消失一半。

可是番薯还是那个番薯,响指还是那个响指,是什么让这两个结合在一起拥有了强大的力量?答案就是:无限手套。电影很精彩,而与之巧合的是,手套的工艺和装饰器模式风格极为相似,所以今天就借来灭霸的手套,研究研究矮人族所制造的产品究竟有多么神奇。

装饰器模式的定义:

允许向一个现有的对象添加新的功能,同时又不改变其结构

🌰:手套每镶嵌一个宝石就增加一个超能力,而之前原本的能力更并不受影响,仍然可以使用。这就是手套无敌的秘密,也就是装饰器模式的魅力所在,让我们看一下用代码是如何实现的。

代码实现

装饰器模式,需要让所有使用的类都来自同一个接口,只有“同一类型”才能互相装饰

所以定义一个 Equipment 接口表示我们所有的装备,action 方法表示每个装备具有的功能

public interface Equipment {
    void action(); 
}

我们定义两种场景: 徒手戴宝石、手套镶嵌宝石

  • 徒手属于(天生自带)装备的一种,所以我们实现 Equipment 接口实现 action 方法
public class Hand implements Equipment {
    @Override
    public void action() {
        System.out.println("手可以戴");
    }
}
  • 手套也是同理
public class Glove implements Equipment {
    @Override
    public void action() {
        System.out.println("手套可以镶嵌");
    }
}
  • 接下来我们定义装饰类也就是 Diamond 宝石抽象类,因为宝石也是装备的一种,所以也需要实现 Equipment。 而我们的装饰有很多种宝石,所以定义装饰类用来实现多态从而装饰对象(手套、手)。
public abstract class Diamond implements Equipment{
    Equipment equipment;

    public Diamond(Equipment equipment) {
        this.equipment = equipment;
    }

    @Override
    public void action() {
        equipment.action();
    }
}

构造器传入被装饰对象,这就是我们开头所提到的,所有使用的类都需要“同一类型”,这样才能将无论是原始对象,还是被装饰过的对象都能以 Equipment 类型传进去,从而再次装饰。

  • 创建三个宝石,实现 Diamond 抽象类,从而具体化每个宝石的功能
public class RedDiamond extends Diamond {
    public RedDiamond(Equipment equipment) {
        super(equipment);
    }

    @Override
    public void action() {
        super.action();
        System.out.println("红色现实宝石");
    }
}

注意在宝石子类里面,每个 action 方法都额外执行了 super.action 方法,每个被装饰对象的 action 方法都会被执行。结合起来,整体功能是这样的👇

在这里插入图片描述

给手套镶嵌绿宝石,在这基础上再镶嵌红宝石。每次执行宝石本身功能之前都会先去执行super.action 直到执行了手套的功能后再返回执行宝石各自的功能,最终执行完所有功能。

  • 以此类推,额外两个宝石类
public class GreenDiamond extends Diamond {
    public GreenDiamond(Equipment equipment) {
        super(equipment);
    }

    @Override
    public void action() {
        super.action();
        System.out.println("绿色时间宝石");
    }
}
public class BlueDiamond extends Diamond {
    public BlueDiamond(Equipment equipment) {
        super(equipment);
    }

    @Override
    public void action() {
        super.action();
        System.out.println("蓝色空间宝石");
    }
}
  • 测试代码:
public class decoratorTest {
    public static void main(String[] args) {
        System.out.println("---------徒手----------");
        Equipment hand = new Hand();
        hand.action();
        System.out.println();
       
        Diamond redDiamond = new RedDiamond(hand);//用红宝石装饰手
        redDiamond.action();
        System.out.println();
        
        Diamond greenAndRedDiamond = new GreenDiamond(redDiamond);//继续用绿宝石装饰
        greenAndRedDiamond.action();
        
        System.out.println("---------戴手套----------");
        Equipment glove = new Glove();
        glove.action();
        System.out.println();
        
        Diamond greenDiamond = new GreenDiamond(glove);//绿宝石装饰手套
        greenDiamond.action();
        System.out.println();
        
        Diamond blueDiamond = new BlueDiamond(glove);//卸下绿宝石,镶嵌蓝宝石
        blueDiamond.action();
    }
}
  • 运行结果:
    在这里插入图片描述

可以看出,每个装饰类可以装饰原本对象,也可以装饰被装饰过的对象,各个装饰类之间相互独立,实现各自功能。

我是 Haoo,一个乐观的码农,撰写有趣的文章。
如果这篇文章帮助到你,请收藏⭐点赞👍加关注👀,跟踪不迷路(🌻◡‿◡)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值