03-JAVA设计模式-装饰模式

news2025/2/28 17:35:50

装饰模式

什么装饰模式

装饰器模式(Decorator Pattern)也叫包装器模式,是一种结构型设计模式,允许用户在不改变对象的情况下,动态地给对象增加一些额外的职责(功能)。装饰器模式相比生成子类更为灵活,因为可以在运行时根据需要动态地添加或删除功能。

职责

  • 动态的为一个对象增加新的功能
  • 装饰模式是一种用于替代继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。

实现细节

  • 抽象组件(Component):定义一个抽象接口,用于规定准备接收附加责任的对象,即可以给这些对象动态地添加职责。
  • 具体组件(ConcreteComponent):实现了抽象组件的接口,定义了一个具体的“被装饰”对象,这个对象可以被装饰器动态地添加功能。
  • 抽象装饰器(Decorator):继承自抽象组件,并持有一个抽象组件的引用。抽象装饰器中声明了与抽象组件相同的方法,并保留了新增功能的接口,以供具体装饰器添加新的功能。
  • 具体装饰器(ConcreteDecorator):实现抽象装饰器所增加的功能,并在调用原有方法时,增加新的功能。

优点

  • 扩展对象功能,比继承灵活,不会导致类个数的急剧增加
  • 可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象
  • 具体构件类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类。

缺点

  • 产生很多小对象。大量小对象占据内存,一定程度上影响性能
  • 装饰器模式容易出错,调试排查比较麻烦

案例

一台普通通话手机,可扩展出具有拍照功能,NCF功能,联网功能

UML

在这里插入图片描述

实现步骤:

  1. 定义一个抽象组件,用于规定准备接收附加功能/职责的方法IPHONE
  2. 定义一个具体组件,实现抽象组件,及实现具备基础功能/职责
  3. 定义一个抽象装饰器,继承抽象组件,并持有一个抽象组件的引用。实现抽象组件接口方法中调用传入接口组件引用的具体实例的方法,达到调用已具备功能/职责
  4. 定义一个/多个具体装饰器,继承抽象装饰器,增加新功能,实现抽象接口时调用原有方法,及新增功能/职责

实现代码

IPhone.java

// 抽象组件:
// *  定义一个手机具备某种功能接口的抽象类
public interface IPhone {
     // 具备功能
     void function();
}

Phone.java

// 具体组件:
// 定义一个具体组件包含最基础的功能:普通手机
public class Phone implements IPhone {
    @Override
    public void function(){
        System.out.println("具备通讯功能");
    };
}

PhoneExtendFunction.java

//抽象装饰器
// 继承自抽象组件,并持有一个抽象组件的引用
public class PhoneExtendFunction implements IPhone{
    // 持有一个抽象组件的引用,调用已具有的功能
    private IPhone phone;

    public PhoneExtendFunction(IPhone phone) {
        this.phone = phone;
    }
    @Override
    public void function() {
        phone.function();
    }
}

InternetFunction.java

// 具体装饰器
// 实现抽象装饰器所增加的功能,并在调用原有方法时,增加新的功能。
public class InternetFunction extends PhoneExtendFunction {
    public InternetFunction(IPhone phone) {
        super(phone);
    }
    public void internet(){
        System.out.println("联网功能");
    }
    @Override
    public void function() {
        super.function();
        internet();
    }
}

NfcFunction.java

// 具体装饰器
// 实现抽象装饰器所增加的功能,并在调用原有方法时,增加新的功能。
public class NfcFunction extends PhoneExtendFunction{
    public NfcFunction(IPhone phone) {
        super(phone);
    }
    public void nfc(){
        System.out.println("NFC功能");
    }
    @Override
    public void function() {
        super.function();
        nfc();
    }
}

PhotographFunction.java

// 具体装饰器
// 实现抽象装饰器所增加的功能,并在调用原有方法时,增加新的功能。
public class PhotographFunction extends PhoneExtendFunction{
    public PhotographFunction(IPhone phone) {
        super(phone);
    }
    public void photograph(){
        System.out.println("摄影功能");
    }
    @Override
    public void function() {
        super.function();
        photograph();
    }
}

TestClient.java

public class TestClient {
    public static void main(String[] args) {
        PhotographFunction phone = new PhotographFunction(new InternetFunction(new NfcFunction(new Phone())));
        phone.function();
    }
}

执行结果:

在这里插入图片描述

装饰器模式和桥接模式的区别

装饰器模式的主要特点是在不改变现有对象结构的情况下,动态地给对象增加一些职责(功能)。装饰器是继承的有力补充,比继承更加灵活。通过使用不同的装饰类和它们的排列组合,可以实现不同的效果。在装饰器模式中,通常会有一个抽象组件和多个具体装饰器,每个装饰器都可以为对象添加新的功能,而且这些装饰器可以灵活地叠加使用。

桥接模式则是将抽象化与实现化分离,使它们可以独立变化。桥接模式包括两个继承体系:抽象部分和实现部分。抽象部分定义了一个接口,规定了实现部分需要实现的方法。实现部分则是具体的实现细节。通过这种方式,桥接模式可以减少派生类的增长,因为你可以将不同的抽象部分和实现部分进行组合,从而得到不同的功能。

两者的主要区别在于:

  • 关注点不同:装饰器模式关注于在不改变对象结构的情况下动态增加功能,而桥接模式关注于将抽象与实现分离,使它们能够独立演化。
  • 结构差异:装饰器模式是通过包装一个已存在的对象,并为其增加新的功能或行为。桥接模式则是通过抽象与实现的分离来组合不同的功能。
  • 行为的叠加性:在装饰器模式中,装饰的行为可以叠加,装饰后的对象可以拥有多个装饰器所添加的功能。而在桥接模式中,行为通常不会叠加,而是通过抽象与实现的组合来提供不同的功能。
  • 稳定性与灵活性:装饰器模式中的对象本身比较稳定,主要是为了增加新功能。而桥接模式本身可能不太稳定,因为实现部分可以独立变化。然而,这也使得桥接模式更加灵活,可以适应更多的变化和需求。

总的来说,装饰器模式和桥接模式在设计和使用上有着明显的区别。装饰器模式更注重在不改变原有结构的基础上增加新功能,而桥接模式更注重抽象与实现的分离和灵活组合

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1585056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【重磅福利】智慧餐饮互联网餐饮行业分析数字化报告大合集共40份(免费下载)

【1】关注本公众号 【2】私信发送 智慧餐饮报告合集 【3】获取本方案合集的下载链接,直接下载即可。

前端学习<四>JavaScript基础——15-内置对象 String:字符串的常见方法

内置对象简介 JavaScript 中的对象分为3种:自定义对象、内置对象、浏览器对象。 前面两种对象:是JS的基础内容,属于 ECMAScript; 第三个浏览器对象:属于JS独有,即 JS 内置的API。 内置对象:就是…

为什么大模型训练都需要GPU?现在都有哪些合适的GPU适合训练大模型?价格如何?

大家有没有这样的疑问,为什么大模型训练需要的是GPU,而不是CPU,而现在市面上,有哪些适合训练的GPU型号,价格如何?下面让我来一一给大家进行介绍。 为什么大模型训练需要GPU,而非CPU?…

设计模式——责任链模式13

责任链模式 每个流程或事物处理 像一个链表结构处理。场景由 多层部门审批,问题分级处理等。下面体现的是 不同难度的问题由不同人进行解决。 设计模式,一定要敲代码理解 传递问题实体 /*** author ggbond* date 2024年04月10日 07:48*/ public class…

Proteus与Multisim哪款更适合51单片机仿真?

选择使用Proteus或Multisim进行51单片机仿真,取决于用户的具体需求、个人偏好以及软件的特点。以下是关于这两款软件的对比分析: 功能和特性 Proteus是一款功能强大的电路设计和仿真软件,它支持多种单片机和微控制器的仿真,包括51…

最新小红书店铺开店带货教程,新手也能跑通全流程(6节课+爆款公式)

爆款标题公式 一、0粉丝个人开店适合哪些赛道,mp4 二、小红书起号爆款逻辑,mp4 三、如何找爆款选题蹭热点.mp4 四、抖音一件代发怎么操作,mp4 五、1688一件代发怎么操作,mp4 六、顾客退货怎么办,mp4 网盘自动获取 链接:https://pan.baidu.com/s/1lpzKPim76qe…

基于java+springboot+vue实现的售楼管理系统(文末源码+Lw)23-255

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本售楼管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息&a…

未提交事务直接返回,导致连接池资源耗尽

错误分析: 我所撰写的代码如下,在使用编程式事务的时候,我未提交或回滚事务就直接返回,因为连接池默认连接数的大小是10,所以到第十一次的时候连接池就会使用完,导致任务无法进行。 Autowired private Ns…

海山数据库(He3DB)原理剖析:浅析OLAP数据库计算引擎中的统计信息

背景: 统计信息在计算引擎的优化器模块中经常被提及,尤其是在基于成本成本优化(CBO)框架中统计信息发挥着至关重要的作用。CBO旨在通过评估执行查询的可能方法,并选择最有效的执行计划来提高查询性能。而统计信息则提…

Qt for MCUs 2.7正式发布

本文翻译自:Qt for MCUs 2.7 released 原文作者:Qt Group高级产品经理Yoann Lopes 翻译:Macsen Wang Qt for MCUs的新版本已发布,为Qt Quick Ultralite引擎带来了新功能,增加了更多MCU平台的支持,并且我们…

全光谱台灯哪个牌子好,2024全光谱护眼台灯推荐

近年来,全光谱台灯悄然跻身于家庭必备品之列,赢得了众多消费者的好评。它们以减轻眼睛疲劳的功效而受到推崇,尽管也有声音质疑其实际效用,认为所谓的益处不过是一种心理安慰。面对这些相互矛盾的观点,许多消费者感到困…

武汉星起航:深挖跨境电商潜力,助力创业者全球拓展

随着全球化进程的加速,跨境电商已成为推动国际贸易发展的新生力量。这一新模式的兴起,得益于互联网、物流和支付技术的深度融合,它不仅打破了地域限制,促进了商品和服务的全球流通,还为消费者带来了更多选择&#xff0…

即插即用篇 | YOLOv5/v7引入Haar小波下采样 | 一种简单而有效的语义分割下采样模块

本改进已集成到 YOLOv5-Magic 框架。 下采样操作如最大池化或步幅卷积在卷积神经网络(CNNs)中被广泛应用,用于聚合局部特征、扩大感受野并减少计算负担。然而,对于语义分割任务,对局部邻域的特征进行池化可能导致重要的空间信息丢失,这有助于逐像素预测。为了解决这个问题…

STC89C52学习笔记(八)

STC89C52学习笔记(八) 综述:本文讲述了LED点阵屏、如何进行数据串行输入,并行输出以及LED点阵屏显示一列多列图形。 一、LED点阵屏 1.介绍 LED点阵屏由多个LED组成,以矩阵形式排列(类似于矩阵键盘&…

分布式锁-redission

5、分布式锁-redission 5.1 分布式锁-redission功能介绍 基于setnx实现的分布式锁存在下面的问题: 重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码…

作业习题

实验代码: import java.util.Scanner;class chazhao {public static void main(String[] args) {Scanner scnew Scanner(System.in);System.out.println("请输入你要的数组");String line sc.nextLine();String[] lineArrline.split(" ");int[…

Mybatis分页查询用PageHelper插件

首先看接口文档需求 看响应数据样例,那么咱们先自定义一个bean来满足这个需求,这里定义PageBean实体类 package com.itheima.pojo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import java.util.List;//分…

uniapp+springboot实现一个简单的音乐播放器移动端+服务端(第一阶段计划有流程制定)

一、项目概述 本项目旨在通过uniapp开发移动端音乐播放器,并利用Spring Boot构建后端服务,实现用户登录、音乐列表获取、音乐播放与暂停、音乐收藏等功能。 二、开发流程 需求分析 确定音乐播放器的核心功能,如用户登录、音乐列表展示、音乐播…

STM32 H7系列学习笔记

必备的API知识 第 1 步:系统上电复位,进入启动文件 startup_stm32h743xx.s,在这个文件里面执行复位中断服务程序。 在复位中断服务程序里面执行函数 SystemInit,在system_stm32h7xx.c 里面。*之后是调用编译器封装好的函数&…

R语言复现:轨迹增长模型发表二区文章 | 潜变量模型系列(2)

培训通知 Nhanes数据库数据挖掘,快速发表发文的利器,你来试试吧!欢迎报名郑老师团队统计课程,4.20直播。 案例分享 2022年9月,中国四川大学学者在《Journal of Psychosomatic Research》(二区,I…