Java设计模式-装饰器模式 理论代码相结合

简介: Java设计模式-装饰器模式 理论代码相结合

微信截图_20220524190240.png

继Java设计模式适配器模式后的装饰器模式来啦,让我们一起看看吧。


会了就当复习丫,不会来一起来看看吧。

很喜欢一句话:“八小时内谋生活,八小时外谋发展”。

如果你也喜欢,让我们一起坚持吧!!

共勉😁


一张旧图,恍惚间念起旧人


设计模式系列


一、装饰器模式介绍


1)引入:


上班族大多都有睡懒觉的习惯,每天早上上班时间都很紧张,于是很多人为了多睡一会,就会用方便的方式解决早餐问题。有些人早餐可能会吃煎饼,煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么“加码”,都还是一个煎饼。在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等,都是装饰器模式。在我们自己行业就是这个东西得加需求啦


在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰器模式来实现。


2)概述


装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式


3)角色结构


  1. 抽象构件(Component):定义一个抽象接口以规范准备接收附加责任的对象。


  1. 具体构件(ConcreteComponent):实现抽象构件,通过装饰角色为其添加一些职责。


  1. 抽象装饰(Decorator):继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。


  1. 具体装饰(ConcreteDecorator):实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。


4)使用场景


1、扩展一个类的功能。


2、动态增加功能,动态撤销。


就是主要为了方便扩展。


5)举个例子


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


微信截图_20220524190429.png


这是一个快餐店的例子,这么咋一看,感觉还可以,但是如果不再局限于炒饭FriedRice和炒面FriedNoodies中,想要做一些扩展,例如加一个炒粉Fried sweet potato powder,就又要额外增加一个整体,再往下重复实现鸡蛋、培根等等的类。增加这么多,就会造成类爆炸,特别多,就非常不合适。


会产生过多的子类。欲知后事如何,请看下文👇。


二、装饰器模式实现


2.1、前言


接下来,我们用装饰器的模式来重构一下代码,看看会产生哪些方面的变化哈。也来一起看看装饰器模式的精髓。


不过图也要改变一下啦,变成这样子的啦:


微信截图_20220524190530.png


我们先来讲讲这张图和上一张图的区别。


  1. 炒饭炒面FriedRice和FriedNoodies还是继承FastFoot


  1. 之前的配料Egg和Bacon不再位于 炒饭炒面下面,而是继承于抽象的配料类下,而配料类Garnish又继承于FastFoot


这么看好像还是少了点东西,结合代码我们一起来看一看。


我们把角色定位一下:


  1. 抽象构件(Component):FastFoot类 即快餐类


  1. 具体构件(ConcreteComponent): FriedRice和FriedNoodies 即炒饭炒面


  1. 抽象装饰(Decorator):Garnish 类


  1. 具体装饰(ConcreteDecorator) Egg和Bacon 类,即鸡蛋和培根为具体装饰类


2.2、代码实现


👇下面看代码一步一步实现看一下:


FastFoot快餐接口:即抽象构件


//快餐接口
public abstract class FastFood {
    private float price;
    private String desc;
    public FastFood() {  }
    public FastFood(float price, String desc) {
        this.price = price;
        this.desc = desc;
    }
    //set、get 方法
    public void setPrice(float price) {  this.price = price; }
    public float getPrice() { return price; }
    public String getDesc() { return desc;  }
    public void setDesc(String desc) {    this.desc = desc;  }
    public abstract float cost();  //获取价格
}


FriedRice和FriedNoodies 即炒饭炒面 即具体构件


//炒饭
public class FriedRice extends FastFood {
    public FriedRice() {
        super(10, "炒饭");
    }
  // 获取价格
    public float cost() {
        return getPrice();
    }
}
//炒面
public class FriedNoodles extends FastFood {
    public FriedNoodles() {
        super(12, "炒面");
    }
  // 获取价格
    public float cost() {
        return getPrice();
    }
}


Garnish 即配料类 抽象装饰


public abstract class Garnish extends FastFood {
    private FastFood fastFood;
    public FastFood getFastFood() {   return fastFood; }
    public void setFastFood(FastFood fastFood) {  this.fastFood = fastFood; }
    public Garnish(FastFood fastFood, float price, String desc) {
        super(price,desc);
        this.fastFood = fastFood;
    }
}


Egg和Bacon 类,即鸡蛋和培根为 具体装饰类


//鸡蛋配料
public class Egg extends Garnish {
    public Egg(FastFood fastFood) {  super(fastFood,1,"鸡蛋");  }
    // 这里是返回了 炒饭加 鸡蛋的钱的
    public float cost() {  return getPrice() + getFastFood().getPrice();  }
    @Override
    public String getDesc() {  return super.getDesc() + getFastFood().getDesc(); }
}
//培根配料
public class Bacon extends Garnish {
    public Bacon(FastFood fastFood) {  super(fastFood,2,"培根"); }
    @Override
    public float cost() {  return getPrice() + getFastFood().getPrice(); }
    @Override
    public String getDesc() {  return super.getDesc() + getFastFood().getDesc();  }
}


测试类:


public class Client {
    public static void main(String[] args) {
        //点一份炒饭
        FastFood food = new FriedRice();
        //花费的价格
        System.out.println(food.getDesc() + " " + food.cost() + "元");
        System.out.println("========");
        //点一份加鸡蛋的炒饭
        FastFood food1 = new FriedRice();
        food1 = new Egg(food1);
        //花费的价格
        System.out.println(food1.getDesc() + " " + food1.cost() + "元");
        System.out.println("========");
        //点一份加培根的炒面
        FastFood food2 = new FriedNoodles();
        food2 = new Bacon(food2);
        //花费的价格
        System.out.println(food2.getDesc() + " " + food2.cost() + "元");
    }
}


这就解决了我们刚开始的一个问题,如果还需要进行扩张,需要增加一个炒河粉 那么只需要写一个炒河粉的类来继承FastFoot快餐类即可,如需增加配料,也只要写个配料类来继承Garnish配料类即可。其他代码均不用改变,完全符合开闭原则。也比原本减少了类的产生。😁


三、总结


1、使用场景


  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:


  • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;


  • 第二类是因为类定义不能继承(如final类)


  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。


  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。


2、优点:


  1. 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用


  1. 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果


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


  1. 装饰器模式完全遵守开闭原则


3、缺点:


  • 装饰器模式会增加许多子类,过度使用会增加程序得复杂性。多层装饰比较复杂。


四、自言自语



你卷我卷,大家卷,什么时候这条路才是个头啊。😇(还是直接上天吧)


有时候也想停下来歇一歇,一直做一个事情,感觉挺难坚持的。😁


你好,如果你正巧看到这篇文章,并且觉得对你有益的话,就给个赞吧,让我感受一下分享的喜悦吧,蟹蟹。🤗


如若有写的有误的地方,也请大家不啬赐教!!


同样如若有存在疑惑的地方,请留言或私信,定会在第一时间回复你。


持续更新中


目录
相关文章
|
14天前
|
设计模式 前端开发 JavaScript
前端必须掌握的设计模式——装饰器模式
装饰器模式是一种结构型设计模式,通过创建新类来包装原始对象,实现在不修改原有结构的前提下扩展新行为。其核心在于“组合”思想,使新功能可“即插即拔”。该模式具有解耦性、灵活性和动态性等特点,广泛应用于类的面向对象编程语言中,如JavaScript的注解和TypeScript的写法。示例中,通过装饰器模式为游戏角色动态添加装备,展示了其强大的扩展性和灵活性。
|
5天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
21 3
|
12天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
50 2
|
27天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
66 5
|
27天前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
53 5
|
27天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
29天前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
26天前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。
|
2天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
4天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。