设计模式07-结构型模式2(装饰模式/外观模式/代理模式/Java)

news2024/11/27 2:42:46

4.4 装饰模式

4.4.1 装饰模式的定义

1.动机:在不改变一个对象本身功能的基础上给对象增加额外的新行为

2.定义:动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活

4.4.2 装饰模式的结构与分析

image-20241029120615417

//抽象构件类
public interface Component {
    public void operation();
}
//具体构建类
public class ConcreteComponent implements Component{
    @Override
    public void operation() {

    }
}
//装饰者类
public class Decorator implements Component {
    private Component component;//要装饰哪个构件
    public Decorator(Component component) {
        this.component = component;
    }
    @Override
    public void operation() {
        component.operation();
    }
}
//具体装饰者类
public class ConcreteDecorator extends Decorator{
    public ConcreteDecorator(Component component) {
        super(component);
    }
    public void preAddOperation() {

    }
    public void operation() {
        preAddOperation();
        super.operation();
        postAddOperation();
    }
    public void postAddOperation() {

    }
}
//客户端
public class Main {
    public static void main(String[] args) {
        //要装饰的构建
        ConcreteComponent component = new ConcreteComponent();
        //创建装饰类
        Decorator decorator = new Decorator(component);
        decorator.operation();
    }
}
  • 装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。

  • 透明装饰模式和半透明装饰模式

**透明装饰模式:**客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型。无法在客户端单独调用新增方法addedBehavior()


**半透明装饰模式:**用具体装饰类型来定义装饰之后的对象,而具体构件使用抽象构件类型来定义。最大的缺点在于不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象(此时已经不再是Component类型了)


4.4.3 装饰模式的案例

某软件公司基于面向对象技术开发了一套图形界面构件库——VisualComponent,该构件库提供了大量基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,用户经常要求定制一些特殊的显示效果,如带滚动条的窗体、带黑色边框的文本框、既带滚动条又带黑色边框的列表框等等,因此经常需要对该构件库进行扩展以增强其功能。现使用装饰模式来设计该图形界面构件库。

image-20241029121904589

//抽象构件类
public interface Component {
    public void display();
}
public class Window implements Component{
    @Override
    public void display() {
        System.out.println("一个窗口");
    }
}
//抽象装饰类
public class Decorator implements Component{
    private Component component;
    public Decorator(Component component) {
        this.component = component;
    }
    @Override
    public void display() {
        component.display();
    }
}
//装饰类
public class BorderDecoration extends Decorator{
    public BorderDecoration(Component component) {
        super(component);
    }
    public void display() {
        addBorder();
        super.display();
    }
    public void addBorder() {
        System.out.println("添加黑色边框");
    }
}
public class ScrollBarDecorator extends Decorator {
    public ScrollBarDecorator(Component component) {
        super(component);
    }
    public void display() {
        addScrollBar();
        super.display();
    }
    public void addScrollBar() {
        System.out.println("添加滚动条");
    }
}
//客户端
public class Main {
    public static void main(String[] args) {
        Window window = new Window();
        //添加滚动条
        ScrollBarDecorator decorator1 = new ScrollBarDecorator(window);
        //添加黑边框
        BorderDecoration decorator2 = new BorderDecoration(decorator1);
        decorator2.display();
    }
}
4.4.4 装饰模式的优缺点
优点缺点
1.装饰模式可以动态的扩展一个对象的功能,且比继承简洁,不会导致类的个数急剧增多1.装饰模式进行系统设计时,会产生很多小对象,占用资源
2.可以对一个对象多次装饰2.比继承更容易犯错
3.构件类和装饰类可以独立变化,无需修改源代码符合开闭原则
4.4.5 装饰模式的适用场景
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责

  • 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式

4.5 外观模式

4.5.1 外观模式的定义

**1.模式动机:**一个客户类需要和多个业务类交互,有时候这些需要交互的业务类会作为一个整体出现,如何简化这种主系统和子系统之间的交互。

**2.模式定义:**为子系统中的一组接口提供一个统一的入口,外观模式定义了一个高层接口,这个接口使得子系统更加容易使用,外部与子系统的通信通过一个统一的外观对象进行。

4.5.2 外观模式的结构与分析

image-20241031150738873

  • 外观对象是迪米特法则的一种具体实现。
  • 子系统符合单一职责原则。
  • 但是当新加入一个子系统时,需要修改子系统角色,这不符合开闭原则。
  • 一个系统可能有多个外观类
  • 不要通过外观类给子系统增加行为
  • 为了在增加外观类的时候符合开闭原则,可以增加一个抽象外观类
public class Facade {
    private SubSystem1 subSystem1 = new SubSystem1();
    private SubSystem2 subSystem2 = new SubSystem2();

    public void method() {
        subSystem1.method1();
        subSystem2.method2();
    }
}
public class SubSystem1 {
    public void method1() {}
}
public class SubSystem2 {
    public void method2() {}
}
4.5.3 外观模式的案例

现在考察一个电源总开关的例子,以便进一步说明外观模式。为了使用方便,一个电源总开关可以控制四盏灯、和一台电视机的启动和关闭。通过该电源总开关可以同时控制上述所有电器设备,使用外观模式设计该系统。

image-20241031153223590
public class Light {
    private String location;
    public Light(String location) {
        this.location = location;
    }
    public void on() {
        System.out.println("打开" + location + "的灯");
    }
    public void off() {
        System.out.println("关闭" + location + "的灯");
    }
}
public class TV {
    public void on() {
        System.out.println("打开电视");
    }
    public void off() {
        System.out.println("关闭电视");
    }
}
public class Facade {
    private Light[] lightArray = new Light[4];

    private TV tv;

    public Facade() {
        lightArray[0] = new Light("客厅");
        lightArray[1] = new Light("厨房");
        lightArray[2] = new Light("卫生间");
        lightArray[3] = new Light("卧室");
        tv = new TV();
    }

    public void on() {
        lightArray[0].on();
        lightArray[1].on();
        lightArray[2].on();
        lightArray[3].on();
        tv.on();
    }

    public void off() {
        lightArray[0].off();
        lightArray[1].off();
        lightArray[2].off();
        lightArray[3].off();
        tv.off();
    }
}
public class Main {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.on();
        facade.off();
    }
}
4.5.4 外观模式的优缺点
优点缺点
1.对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易1.不能很好地限制客户端直接使用子系统类
2.对客户端和子系统进行解耦2.如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则
3.子系统的变化独立,不会影响到其他子系统和客户端
4.5.5 外观模式的适用场景
  • 要为访问一系列复杂的子系统提供一个简单入口

  • 客户端程序与多个子系统之间存在很大的依赖性

  • 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而是通过外观类建立联系,降低层之间的耦合度

4.6 代理模式

4.6.1 代理模式的定义

**1.模式动机:**通过引入一个新的对象来实现对真实对象的操作,或者将新的对象作为真实对象的一个替身,引入代理对象来间接访问一个对象

2.模式定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用

4.6.2 代理模式的结构与分析
image-20241031154722704
public interface Subject {
    public void request();
}
public class Real implements Subject{
    @Override
    public void request() {}
}
public class Proxy implements Subject{
    private Real real = new Real();
    public void preRequest() {}
    @Override
    public void request() {
        preRequest();
        real.request();
        postRequest();
    }
    public void postRequest() {}
}
4.6.3 代理模式的案例
  • 保护代理:

在一个论坛中已注册用户和游客的权限不同,已注册的用户拥有发帖、修改自己的注册信息、修改自己的帖子等功能;而游客只能看到别人发的帖子,没有其他权限。使用代理模式来设计该权限管理模块。

image-20241031160121403

public interface Permission {
    public void readBolg();
    public void writeBolg();
    public void updateBolg();
    public void updateUserInfo();
}

public class RealPermission implements Permission{
    @Override
    public void readBolg() {
        System.out.println("阅读博客");
    }

    @Override
    public void writeBolg() {
        System.out.println("写博客");
    }

    @Override
    public void updateBolg() {
        System.out.println("修改博客");
    }

    @Override
    public void updateUserInfo() {
        System.out.println("修改用户信息");
    }
}


public class ProxyPermission implements Permission{
    private int state;
    private RealPermission permission;

    public ProxyPermission(int state) {
        this.state = state;
        permission = new RealPermission();
    }

    @Override
    public void readBolg() {
        permission.readBolg();
    }

    @Override
    public void writeBolg() {
        if (state == 0) {
            System.out.println("游客模式不能写博客");
        } else {
            permission.writeBolg();
        }
    }

    @Override
    public void updateBolg() {
        if (state == 0) {
            System.out.println("游客模式不能更改博客");
        } else {
            permission.updateBolg();
        }
    }

    @Override
    public void updateUserInfo() {
        if (state == 0) {
            System.out.println("游客模式不能更改信息");
        } else {
            permission.updateUserInfo();
        }
    }
}
4.6.4 代理模式的优缺点
优点缺点
1.能够协调调用者和被调用者,在一定程度上降低了系统的耦合度1.增加了代理对象,有些类型的代理模式可能会造成请求的处理速度变慢
2.客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则2.实现代理模式需要额外的工作,而且有些代理模式的实现过程较为复杂
4.6.5 代理模式的适用场景
代理模式描述
远程代理当客户端对象需要访问远程主机中的对象时
虚拟代理当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时
缓冲代理当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时
保护代理当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时
智能引用代理当需要为一个对象的访问(引用)提供一些额外的操作
防火墙代理保护目标不让恶意用户接近。
同步化代理使几个用户能够同时使用一个对象而没有冲突。
Copy-on-Write代理把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作。

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

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

相关文章

Spring @RequestMapping 注解

文章目录 Spring RequestMapping 注解一、引言二、RequestMapping注解基础1、基本用法2、处理多个URI 三、高级用法1、处理HTTP方法2、参数和消息头处理 四、总结 Spring RequestMapping 注解 一、引言 在Spring框架中,RequestMapping 注解是构建Web应用程序时不可…

【Linux】IPC 进程间通信(一):管道(匿名管道命名管道)

✨ 无人扶我青云志,我自踏雪至山巅 🌏 📃个人主页:island1314 🔥个人专栏:Linux—登神长阶 ⛺️ 欢迎关注:👍点赞 &#…

单片机串口接收状态机STM32

单片机串口接收状态机stm32 前言 项目的芯片stm32转国产,国产芯片的串口DMA接收功能测试不通过,所以要由原本很容易配置的串口空闲中断触发DMA接收数据的方式转为串口逐字节接收的状态机接收数据 两种方式各有优劣,不过我的芯片已经主频跑…

信息学科平台系统开发:基于Spring Boot的最佳实践

3系统分析 3.1可行性分析 通过对本基于保密信息学科平台系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本基于保密信息学科平台系统采用Spring Boot框架&a…

探索 ONLYOFFICE 8.2 版本:更高效、更安全的云端办公新体验

引言 在当今这个快节奏的时代,信息技术的发展已经深刻改变了我们的工作方式。从传统的纸质文件到电子文档,再到如今的云端协作,每一步技术进步都代表着效率的飞跃。尤其在后疫情时代,远程办公成为常态,如何保持团队之间…

51c自动驾驶~合集4

我自己的原文哦~ https://blog.51cto.com/whaosoft/12413878 #MCTrack 迈驰&旷视最新MCTrack:KITTI/nuScenes/Waymo三榜单SOTA paper:MCTrack: A Unified 3D Multi-Object Tracking Framework for Autonomous Driving code:https://gi…

STM32HAL-最简单的长、短、多击按键框架(多按键)

概述 本文章使用最简单的写法实现长、短、多击按键框架,非常适合移植各类型单片机,特别是资源少的芯片上。接下来将在stm32单片机上实现,只需占用1个定时器作为时钟扫描按键即可。 一、开发环境 1、硬件平台 STM32F401CEU6 内部Flash : 512Kbytes,SARM …

【论文精读】LPT: Long-tailed prompt tuning for image classification

🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀论文精读_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 摘要 2. …

队列的模拟实现

概念: 队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为 队尾( Tail/Rear ) 出队列&a…

Centos安装配置Jenkins

下载安装 注意:推荐的LTS版本对部分插件不适配,直接用最新的版本,jenkins还需要用到git和maven,服务器上已经安装,可查看参考文档[1]、[2],本次不再演示 访问开始使用 Jenkins 下载jenkins 上传至服务器…

在Python中最小化预测函数的参数

在 Python 中,最小化预测函数的参数通常涉及使用优化算法来调整模型的参数,以减少预测误差。下面介绍几种常见的方法来实现这一目标,主要使用 scipy 和 numpy 库。 1、问题背景 我正在尝试通过解决自己想出的问题来学习Python,我…

统信UOS系统应用开发

包括cpu 、内存 、安全等接口描述。 文章目录 一、内存管理非文件形式的内存动态函数库调用接口二、cpu内置安全飞腾国密加速硬件用户态驱动API说明真随机数真随机数三、cpu多核调度cpu亲和性获取接口用于cpu set集操作的相关宏定义一、内存管理 非文件形式的内存动态函数库调…

postman 获取登录接口中的返回token并设置为环境变量的方法 postman script

postman是一个比较方便的API开发调试工具, 我们在访问API时一般都需要设置一个token来对服务进行认证, 这个token一般都是通过登录接口来获取。 这个postman脚本放到登录接口的sctipt--> post-response里面即可将登陆接口中返回的token值设置到postma…

《华为工作法》读书摘记

无论做什么事情,首先要明确的就是做事的目标。目标是引导行动的关键,也是证明行动所具备的价值的前提,所以目标管理成了企业与个人管理的重要组成部分。 很多时候,勤奋、努力并不意味着就一定能把工作做好,也并不意味…

【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏

【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏 目录 文章目录 【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏目录摘要研究背景问题与挑战如何解决创新点算法模型实验效果代码推荐阅读指数&…

Tomcat 和 Docker部署Java项目的区别

在 Java 项目部署中,Tomcat 和 Docker 是两种常见的选择。虽然它们都可以用来运行 Java 应用,但它们在定位、部署方式、依赖环境、资源隔离、扩展性和适用场景等方面有显著区别。 1. 功能定位 1.1 Tomcat Apache Tomcat 是一种轻量级的 Java 应用服务器…

基于SSM的学生选课系统+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

Java I/O流详解

文章目录 I/O流概念I/O流的分类字节流(Byte Streams)字节字节流概述方法主要类和继承关系示例代码字节流读取文件 字符流字符流概述子类Reader1.FileReader:2.CharArrayReader:3.StringReader:4.InputStreamReader&…

基于Multisim数字频率计频率范围0-9999HZ电路(含仿真和报告)

【全套资料.zip】数字频率计仿真电路设计Multisim仿真设计数字电子技术 文章目录 功能一、Multisim仿真源文件二、原理文档报告资料下载【Multisim仿真报告讲解视频.zip】 功能 1.采用纯数字电路,非单片机。 2.频率计测量的频率范围0-9999HZ。 3.使用数码管进行频…

Python画笔案例-095 绘制鼠标画笔

1、绘制 鼠标画笔 通过 python 的turtle 库绘制 鼠标画笔,如下图: 2、实现代码 绘制 鼠标画笔,以下为实现代码: """鼠标画笔.py本程序可以用鼠标指针在屏幕上画画儿。 """ import turtlescreen = turtle.getscreen() screen.setup(