Java 23种设计模式(7.结构型模式-装饰者模式)

news2024/10/7 14:26:25

结构型模式-装饰者模式

代码分析

类图

在这里插入图片描述

代码

abstract class Component {
    abstract void operation();
}
public class ConcreteComponent extends Component {
    void operation() {
        System.out.println("具体类");
    }
}

public class Decorator extends Component{
    private Component component;
    void operation() {
        if(component!=null){
            component.operation();
        }
    }

    public Component getComponent() {
        return component;
    }

    public void setComponent(Component component) {
        this.component = component;
    }
}
public class ConcreteDecoratorA extends Decorator{
    private String addedState;
    public void operation(){
        super.operation();
        addedState="new state";
        System.out.println("具体装饰对象A的操作");
    }
}
public class ConcreteDecoratorB extends Decorator{
    private void addedBehavior(){

    }
    public void operation(){
        super.operation();
        System.out.println("具体装饰对象B的操作");
        addedBehavior();

    }
}

public class Client {
    public static void main(String[] args) {
//        Component c = new ConcreteComponent();
//        c.operation();
//        System.out.println("=============");
//        c = new ConcreteDecoratorA();
//        c.operation();
//        System.out.println("=============");
//        c= new ConcreteDecoratorB();
//        c.operation();
//两种方式都可以,以下是通过setComponent()
        Component c = new ConcreteComponent();
        ConcreteDecoratorA A = new ConcreteDecoratorA();
        ConcreteDecoratorB B = new ConcreteDecoratorB();
        A.setComponent(c);
        B.setComponent(A);
        B.operation();

    }
}

运行结果

具体类
具体装饰对象A的操作
具体装饰对象B的操作

1.概述

我们先来看一个快餐店的例子。
快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,- 每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦。

使用继承的方式存在的问题

  • 扩展性不好
    如果要再加一种配料(火腿肠),我们就会发现需要给FriedRice和FriedNoodles分别定义一
    个子类。如果要新增一个快餐品类(炒河粉)的话,就需要定义更多的子类。
  • 产生过多的子类

指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。

2.结构

装饰(Decorator)模式中的角色:

抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任

3. 类图

在这里插入图片描述

4. 代码

abstract class FastFood {

    private float price;
    private String desc;

    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    abstract float cost();
    
    public FastFood(float price,String desc) {
        this.price = price;
        this.desc = desc;
    }
    public FastFood() {

    }
}

public class FriedRice extends FastFood{
    float cost;
    public FriedRice() {
        super(12,"rice");
    }

    @Override
    float cost() {
        return getPrice();
    }
}

public class FriedNoodles extends FastFood{
    public FriedNoodles() {
        super(15,"noodles");
    }

    @Override
    float cost() {
        return getPrice();
    }
}

public class Garnish extends FastFood{
    private FastFood fastFood;

    public void setFastFood(FastFood fastFood) {
        this.fastFood = fastFood;
    }

    public FastFood getFastFood() {
        return fastFood;
    }

    public Garnish(FastFood fastFood,float price,String desc) {
        super(price,desc);
        this.fastFood= fastFood;

    }

    @Override
    float cost() {
        return 0;
    }
}

public class Egg extends Garnish{
    public Egg(FastFood fastFood) {
        super(fastFood, 1, "egg");
    }
   public float cost(){
        return getFastFood().cost()+ getPrice();
    }
    public String getDesc(){
        return super.getDesc()+getFastFood().getDesc();
    }
}

public class Bacon extends Garnish{
    public Bacon(FastFood fastFood) {
        super(fastFood, 1, "bacon");
    }
    public float cost(){
        return getFastFood().cost()+ getPrice();
    }
    public String getDesc(){
        return super.getDesc()+getFastFood().getDesc();
    }
}

public class Client {
    public static void main(String[] args) {
        //点一份炒饭
        FastFood food= new FriedNoodles();
        System.out.println(food.getDesc() + "  " + food.cost() + "元");
        System.out.println("===============");
        //在上面的炒饭中加一个鸡蛋
        food = new Egg(food);
        System.out.println(food.getDesc() + "  " + food.cost() + "元");
        //再加一个鸡蛋
        food = new Egg(food);
        System.out.println(food.getDesc() + "  " + food.cost() + "元");
        System.out.println("================");
        food = new Bacon(food);
        System.out.println(food.getDesc() + "  " + food.cost() + "元");
    }
}

运行结果:

noodles  15.0===============
eggnoodles  16.0元
eggeggnoodles  17.0================
baconeggeggnoodles  18.0

5.优缺点

  • 饰者模式可以带来比继承更加灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性,完美的遵循开闭原则,继承是静态的附加责任,装饰者则是动态的附加责任。
  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能

6. 使用场景

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
    不能采用继承的情况主要有两类:
    • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类定义不能继承(如final类)
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

7.JDK源码解析

IO流中的包装类使用到了装饰者模式。BufferedInputStreamBufferedOutputStream
BufferedReaderBufferedWriter
我们以BufferedWriter举例来说明,先看看如何使用BufferedWriter

public class Demo {
public static void main(String[] args) throws Exception{
	//创建BufferedWriter对象
	//创建FileWriter对象
	FileWriter f = new FileWriter("C:\\Users\\Desktop\\a.txt");
	BufferedWriter b = new BufferedWriter(f);
	//写数据
	b.write("hello Buffered");
	b.close();
	}
}

在这里插入图片描述

BufferedWriter使用装饰者模式对Writer子实现类进行了增强,添加了缓冲区,提高了写数
据的效率。

8.代理和装饰者的区别

静态代理和装饰者模式的区别:

相同点:

  • 都要实现与目标类相同的业务接口
  • 在两个类中都要声明目标对象
  • 都可以在不修改目标类的前提下增强目标方法

不同点:

  • 目的不同:
    装饰者是为了增强目标对象 静态代理是为了保护和隐藏目标对象
  • 获取目标对象构建的地方不同 :
    装饰者是由外界传递进来,可以通过构造方法传递
    静态代理是在代理类内部创建,以此来隐藏目标对象

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

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

相关文章

为向IPv6过渡的组织发布安全指南

美国国家安全局 (NSA) 已发布指南,以帮助国防部 (DoD) 和其他系统管理员识别和减轻与过渡到互联网协议版本 6 (IPv6) 相关的网络风险。 IPv6 由互联网工程任务组 (IETF) 开发,是用于识别和定位系统并在互联网上路由流量的协议的最新版本,提供…

统计学习方法 学习笔记(5)决策树

决策树5.1.决策树模型与学习5.2.特征选择5.3.决策树的生成5.4.决策树的剪枝5.5.CART算法决策树基本概述: 算法类别:一种基本的分类和回归方法;基本结构:呈现树形结构,在分类问题中表示基于特征对实例进行分类的过程。…

云原生之使用docker部署Postgresql数据库

云原生之使用docker部署Postgresql数据库一、Postgresql介绍1.PostgreSQL简介2.PostgreSQL的特点二、检查本地docker环境1.检查系统版本2.检查docker版本3.检查docker状态三、下载Postgresql镜像四、部署Postgresql数据库1.创建Postgresql容器2.查看Postgresql容器状态3.查看Po…

通配符的匹配很全面, 但无法找到元素 ‘context:component-scan‘ 的声明。

HTTP状态 500 - 内部服务器错误 类型 异常报告 消息 Servlet[springMVC]的Servlet.init()引发异常 描述 服务器遇到一个意外的情况,阻止它完成请求。 例外情况 javax.servlet.ServletException: Servlet[springMVC]的Servlet.init&#x…

一文看懂Linux基础

文章目录什么是Linux操作系统window和linux的对比快照的拍摄Linux的文件结构kali Linux的简单介绍基础命令vim命令文件权限kali的常见工具查看命令1.查看操作:2.删除操作:3.复制操作:4.移动操作:5.重命名操作:7.上传文…

【时间复杂度和空间复杂度】

1.时间复杂度时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个数学函数,它定量描述了该算法的额外运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起…

Linux系统用户和权限

文章目录root用户用户、用户组管理查看权限控制修改权限控制 - chmod修改权限控制 - chownroot用户 无论是Windows、MacOS、Linux均采用多用户的管理模式进行权限管理。 在Linux系统中,拥有最大权限的账户名为:root(超级管理员) …

机器学习(七):Azure机器学习模型搭建实验

文章目录 Azure机器学习模型搭建实验 前言 Azure平台简介 Azure机器学习实验 Azure机器学习模型搭建实验 前言 了解Azure机器学习平台,知道机器学习流程。 Azure平台简介 Azure Machine Learning(简称“AML”)是微软在其公有云Azure上推…

前缀树 字典树 TrieTree的学习与模拟实现

目录前言前缀树介绍C实现核心思想前缀树的大致框架前缀树插入字符串前缀树查找完整的字符串前缀树查找前缀匹配的字符串前缀树删除完整字符串总结完整代码前言 哥们在去年12月的一次实习面试的时候,远在旧金山的一家美企CTO面试我,岗位在西安&#xff0…

【MySQL进阶】MySQL视图详解

序号系列文章6【MySQL基础】MySQL单表操作详解7【MySQL基础】运算符及相关函数详解8【MySQL基础】MySQL多表操作详解9【MySQL进阶】MySQL事务详解文章目录前言1,视图1.1,视图概述1.2,视图使用环境1.3,视图创建格式1.4,…

【C语言课堂】 函数递归

欢迎来到 Claffic 的博客 💞💞💞 前言: 时隔多日,来还欠大家的 C 语言学习啦,上期讲了函数,其实函数中应该包括函数递归的,这里单独拿出来讲解的原因是函数递归属于重难知识&#xf…

【编程入门】开源记事本(Flutter版)

背景 前面已输出多个系列: 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 本系列对比云笔记,将更为简化,去掉了网络调用&#xff0…

数据结构入门(力扣算法)

数据结构入门前面的题号为力扣的题号数组的217. 存在重复元素53. 最大子数组和1. 两数之和88. 合并两个有序数组350. 两个数组的交集 II121. 买卖股票的最佳时机566. 重塑矩阵118. 杨辉三角36. 有效的数独73. 矩阵置零字符串的387. 字符串中的第一个唯一字符383. 赎金信242. 有…

LeetCode 437. 路径总和 III

LeetCode 437. 路径总和 III 给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的&#xff…

JUC面试(十一)——LockSupport

可重入锁 可重入锁又名递归锁 是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提,锁对象得是同一个对象),不会因为之前已经获取过的锁还没释放而阻塞。 Java中ReentrantLock和synchronized都是可重入锁&am…

第一章 概述

第一章 概述 1.1 计算机网络在信息时代中的作用 21世纪的一些重要特征 数字化,网络化和信息化 以网络为核心的信息时代 互联网的两个重要基本特点 连通性共享(资源共享) 1.2 互联网概述 计算机网络由若干个结点货连接这些结点的链路组成…

【唐诗学习】四、边塞诗派代表

四、边塞诗派代表 边塞诗派起源 盛唐是中国历史上一个空前的盛世,国库丰盈,社会十分安定,百姓的幸福指数高。 盛唐是中国历史上一个空前的盛世,国库丰盈,社会十分安定,百姓的幸福指数高。唐太宗以后的几个…

Citadel——Dusk网络的Zero-Knowledge KYC解决方案

1. 引言 近期,Dusk网络宣布其已支持名为Citadel的Zero-Knowledge KYC解决方案,使得用户和机构可控制其权限以及个人信息分享。该架构可用于all claim-based KYC requests,并让用户完全控制他们共享的信息以及与谁共享信息,同时完…

详解Java中的BIO、NIO、AIO

1、 详解Java中的BIO、NIO、AIO 1.1、引言 IO流是Java中比较难理解的一个知识点,但是IO流在实际的开发场景中经常会使用到,比如Dubbo底层就是NIO进行通讯。本文将介绍Java发展过程中出现的三种IO:BIO、NIO以及AIO,重点介绍NIO。…

【c语言进阶】常见的静态通讯录

🚀write in front🚀 📜所属专栏:c语言学习 🛰️博客主页:睿睿的博客主页 🛰️代码仓库:🎉VS2022_C语言仓库 🎡您的点赞、关注、收藏、评论,是对我…