Java结构性设计模式中的装饰器模式介绍使用
作者:丨Jack_Chen丨 发布时间:2022-04-08 06:30:00
装饰器模式
概述
装饰器模式(Decorator Pattern)也称为包装模式(Wrapper Pattern),属于结构型模式。
它是指在不改变原有对象的基础之上,允许向一个现有的对象添加新的功能,同时又不改变其结构,作为现有的类的一个包装。
这种模式创建一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
提供了比继承更有单性的替代方案,进行扩展原有对象的功能。
装饰器模式的核心是功能扩展。使用装饰器模式可以透明且动态地扩展类的功能。
装饰器模式主要用于诱明且动态地扩展类的功能。
实现原理
让装饰器实现被包装类相同的接口,使得装饰器与被扩展类类型一致,并在构造函数中传入该接口对象,然后就可以在接口需要实现的方法中在被包装类对象的现有功能上添加新功能。
由于装饰器与被包装类属于同一类型,且构造函数的参数为其实现接口类,因此装饰器模式具备嵌套扩展功能,因此就能使用装饰器模式一层层的对最底层被包装类进行功能扩展。
在JDK中,IO相关包下大量使用装饰器模式,如BufferedReader、InputStream、OutputStream等类
主要角色
装饰器模式主要包含4种角色
1.抽象组件(Component)
抽象组件可以是一个接口或者抽象类,其充当被装饰类的原始对象,规定了被装饰对象的行为。
2.具体组件(ConcreteComponent)
具体组件实现/继承抽象组件的一个具体对象,即被装饰对象。
3.抽象装饰器(Decorator)
通用的装饰具体组件的装饰器,其内部必然有一个属性指向抽象组件;其实现一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个抽象组件,这是强制的通用行为。
如果系统中装饰逻辑单一,并不需要实现许多装饰器,那么可以直接省略该类,而直接实现一个具体装饰器即可。
4.具体装饰器(ConcreteDecorator)
抽象装饰器的具体实现类,理论上,每个具体组件都扩展了抽象组件对象的一种功能。
应用场景
1.用于扩展一个类的功能或给一个类添加附加职责。
2.动态的给一个对象添加功能,这些功能可以再动态的澈销。
3.需要为一批的兄弟类进行改装或加装功能。
优缺点
优点:
1.装饰器是继承的补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用。
2.装饰器完全遵守开闭原则。
缺点:
1.会出现更多的代码,更多的类,增加程序复杂性。
2.通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。
3.动态装饰时,多层装饰时会更复杂。
装饰器模式的基本使用
创建抽象组件
创建Phone抽象类
public abstract class Phone {
public abstract String call();
public abstract double price();
}
具体组件
创建最基本具有打电话功能的手机
public class BasePhone extends Phone {
@Override
public String call() {
return "BasePhone call";
}
@Override
public double price() {
return 0.1;
}
}
抽象装饰器
创建一个抽象装饰器来扩展该只具备基本功能的手机
public abstract class PhoneDecorator extends Phone {
private Phone phone;
public PhoneDecorator(Phone phone) {
this.phone = phone;
}
@Override
public String call() {
return phone.call();
}
@Override
public double price() {
return phone.price();
}
/**
* 扩展功能
*/
public abstract void sendMsg();
}
具体装饰器
public class SatellitePhoneDecorator extends PhoneDecorator{
public SatellitePhoneDecorator(Phone phone) {
super(phone);
}
public void sendMsg() {
System.out.println("PhoneCallDecorator sendMsg");
}
@Override
public String call() {
return "SatellitePhone call";
}
@Override
public double price() {
return super.price()+100;
}
}
客户端调用
public static void main(String[] args) {
// 创建需要被装饰的原始对象(即要被装饰的对象)
Phone phone = new BasePhone();
System.out.println("使用: "+phone.call()+" 方式打电话,每分钟单价:" + phone.price());
// 给对象透明的增加额外功能并调用
PhoneDecorator phoneDecorator = new SatellitePhoneDecorator(phone);
System.out.println("使用: "+phoneDecorator.call()+" 方式打电话,每分钟单价:" + phoneDecorator.price());
// 装饰器也可以装饰具体的装饰对象,相当于给对象在增加的功能基础上在添加功能,这里体现在单价100.1基础上再+100
PhoneDecorator satellitePhoneDecorator = new SatellitePhoneDecorator(phoneDecorator);
System.out.println("使用: "+satellitePhoneDecorator.call()+" 方式打电话,每分钟单价:" + satellitePhoneDecorator.price());
satellitePhoneDecorator.sendMsg();
}
使用: BasePhone call 方式打电话,每分钟单价:0.1
使用: SatellitePhone call 方式打电话,每分钟单价:100.1
使用: SatellitePhone call 方式打电话,每分钟单价:200.1
PhoneCallDecorator sendMsg
来源:https://blog.csdn.net/qq_38628046/article/details/126131404
猜你喜欢
- /// <summary> /// 遍历Co
- openid可以标识一个用户,session_key会变,所以来获取一下openid。openid不能在微信小程序中直接获取,需要后台发送请
- 谨记:Url表只储存受保护的资源,不在表里的资源说明不受保护,任何人都可以访问1、MyFilterInvocationSecurityMet
- java读写ini文件、FileOutputStream在上课让学生练习文件读写,就让他们做了一个使用文件保存账号和密码的练习,有一个比较爱
- Java 17 更新了,作为一个 10 年的 Java 程序员,还是有亿点点兴奋的,Kotlin 的群里面也是各种讨论 Java 的新特性。
- 前言入职新公司到现在也有一个月了,完成了手头的工作,前几天终于有时间研究下公司旧项目的代码。在研究代码的过程中,发现项目里用到了Spring
- mybatis if test判断BigDecimal遇到的坑<update id="test" paramete
- 本文实例讲述了Java文本文件操作方法。分享给大家供大家参考。具体分析如下:最初Java是不支持对文本文件的处理的,为了弥补这个缺憾而引入了
- 应用场景最近社区总有人发文章带上小广告,严重影响社区氛围,好气!对于这种类型的用户,就该永久拉黑!社区的安全框架使用了 spring-sec
- 关键字:spring容器加载完毕做一件事情(利用ContextRefreshedEvent事件)应用场景:很多时候我们想要在某个类加载完毕时
- 在Java编程中经常碰到类型转换,对象类型转换主要包括向上转型和向下转型。向上转型我们在现实中常常这样说:这个人会唱歌。在这里,我们并不关心
- 本文实例讲述了C#实现3步手动建DataGridView的方法。分享给大家供大家参考。具体如下:DataView dvCmControlIn
- 为什么要重复造轮子你可能会问,Spring已经自带了全局异常拦截,为什么还要重复造轮子呢?这是个好问题,我觉得有以下几个原因装逼Spring
- 问题:在web里面用iframe连接一个html文件 - html文件里面是超链接 -&nb
- 1. 需求和思路最近要用java制作一个数据集,每一行是一个样本,格式是csv。用了一下java类的相关概念,把csv文件里的每一行,即每一
- SSO :同一个帐号在同一个公司不同系统上登陆 使用SpringSecurity实现类似于SSO登陆系统是十分简单的 下面我就搭
- 使用HTTPclient访问url获得数据最近项目上有个小功能需要调用第三方的http接口取数据,用到了HTTPclient,算是做个笔记吧
- 0x01 新建SpringBoot项目1. 新建maven工程ps:在上一教程的基础上操作,就不用新建项目了,请参考文章:SpringBoo
- Java序列化JSON时long型数值,会出现精度丢失的问题。原因:java中得long能表示的范围比js中number大,也就意味着部分数
- android线程消息机制主要由Handler,Looper,Message和MessageQuene四个部分组成。平常在开发中,我们常用来