【设计模式-结构型】装饰器模式

一、什么是装饰器模式

装饰器模式(Decorator Pattern)是一种结构型设计模式,它的核心思想是在不改变原有对象结构的情况下,动态地给对象增加一些功能,从而达到扩展功能的目的。举个例子,今天在家妈妈给蒸馒头。馒头蒸的过程中,妈妈去收拾衣服了。突然想起来,馒头好了,就跟你说:"帮我把馒头拿出来。"这个时候馒头特别烫,如果不烫其实用我们的手是可以拿出来的,但是这个时候光用手拿不行。所以我们想了个办法,找了一个手套,从而把馒头拿了出来。这个过程就类似于装饰器模式,手套相当于装饰器,给手(原有对象)增加了隔热的功能,使得手能够处理原本无法直接处理的烫馒头。

二、为什么使用装饰器模式

基于上面的馒头场景,我们讨论一下为什么使用装饰器模式(为什么要戴手套):

  1. 动态扩展(撤销)功能 :当需要在运行时为对象动态添加功能时,装饰器模式是一个很好的选择。例如,比如应对热馒头去拿的时候要隔热功能,不想隔热还可以直接上手。但是装饰的多了,手不热吗?手不累吗?所示要适当添加。别为了拿馒头装了一堆东西反而得不偿失。

  2. 避免子类爆炸 :如果通过继承来扩展功能,可能会导致子类数量急剧增加,使得系统变得复杂且难以维护。装饰器模式可以避免这种情况,通过组合的方式动态添加功能(继承关系的替代)。

  3. 保持原有接口不变 :装饰器模式可以在不改变原有对象接口的情况下,增加新的功能,这使得客户端代码可以透明地使用被装饰的对象,而不需要修改客户端代码。(拿馒头的手,拿的功能不变)

三、装饰器模式示例

  1. Component(抽象组件):定义了被装饰对象的接口,所有具体的组件和装饰器都实现这个接口。

    java 复制代码
    //我就是一个手,人们定义我叫手,收能拿东西
    public interface Hand {
        void pickUp(Object object) throws Exception;
    }
  2. ConcreteComponent(具体组件):实现了Component接口的具体组件,是被装饰的对象。

    java 复制代码
    //我是一个赤裸裸真是长在身上的手,人们说手可以拿东西,我也可以
    public class BareHand implements Hand {
        @Override
        public void pickUp(Object object) throws Exception {
            if (object instanceof HotBun) {
                throw new Exception("我擦,太热了!");
            }
            System.out.println("Picked up " + object.getClass().getSimpleName() + " with bare hands.");
        }
    }
  3. Decorator(装饰器抽象类):也实现了Component接口,持有一个Component对象的引用,通过组合的方式动态地为Component对象添加新的功能。

    java 复制代码
    //其实手上没准可以加点东西 
    public abstract class HandDecorator implements Hand {
        protected Hand hand;
    
        public HandDecorator(Hand hand) {
            this.hand = hand;
        }
    
        @Override
        public void pickUp(Object object) throws Exception {
            hand.pickUp(object);
        }
    }
  4. ConcreteDecorator(具体装饰器):实现了Decorator的具体装饰器,负责给Component对象添加具体的装饰功能。

    java 复制代码
    //我是手套
    public class GloveDecorator extends HandDecorator {
        public GloveDecorator(Hand hand) {
            super(hand);
        }
    
        @Override
        public void pickUp(Object object) throws Exception {
            System.out.println("戴上手套去拿 " + object.getClass().getSimpleName());
            hand.pickUp(object);
        }
    }
  5. 客户端

    java 复制代码
    //我是一个热馒头
    public class HotBun {
        // 烫馒头的具体实现
    }
    java 复制代码
    public class Main {
        public static void main(String[] args) {
            Hand bareHand = new BareHand();
            try {
                bareHand.pickUp(new HotBun());
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
    
            // 使用手套装饰手
            Hand glovedHand = new GloveDecorator(bareHand);
            try {
                glovedHand.pickUp(new HotBun());
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
    
    //输出
    我擦,太热了!
    戴上手套去拿热馒头
    我擦,太热了!
相关推荐
涉密IT资质笔记1 分钟前
涉密资质投入产出分析模型:时间成本、四块成本构成与 ROI 决策框架
java·开发语言·算法
木井巳3 分钟前
【BFS 解决拓扑排序】火星词典
java·算法·leetcode·广度优先·宽度优先·图搜索算法
霸道流氓气质4 分钟前
Java调用StableDiffusion/ComfyUI图像生成:DAG工作流编排、WebSocket实时进度与Flux模型集成的生产级实战
java·websocket·stable diffusion
北风toto14 分钟前
KMP 算法详解:从暴力匹配到 O(n+m) 的字符串搜索
java·开发语言·算法
weixin1997010801615 分钟前
《京东JOS API:落地方案、接口边界与业务踩坑 —— 联盟免费 vs 商家按量的双轨制》(附python源码)
java·网络·python
衡石科技18 分钟前
从语义准备到模型验收:HENGSHI SENSE Data Agent 的 RAG 与部署工程实践
java·大数据·人工智能·数据分析·rag
G018_star sky♬18 分钟前
java学习日记-多态与好玩的写法
java
撸串-研究生21 分钟前
面向景区的综合服务管理平台设计——以稻城亚丁景区为例【附源码】
java·开发语言·vue.js·前后端分离·稻城亚丁景区
geovindu29 分钟前
rust: pool Pattern (续)
开发语言·后端·设计模式·rust·对象池简写模式
一条泥憨鱼31 分钟前
拦截器与过滤器:一次请求穿过 Spring 时,会先经过谁呢
java·开发语言·后端·spring