[DP]Decorator设计模式

侯捷C++八部曲笔记(三、设计模式) 阅读详情

关于本期的Decorator设计模式,我想不出比较合适准确贴切的例子啊。

不如就这么直接跳过了吧!!!!



那么就举一个不贴切的例子吧。

我们有一个加减乘除计算器,但是我们需要一个新功能——求余运算,那么我们该怎么做呢?

如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能,你也许会仅仅继承这个类来产生一个新类—这建立在额外的代码上。

对于继承来说,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。

如果 你希望改变一个已经初始化的对象的行为,你怎么办?或者,你希望继承许多类的行为,改怎么办?前一个,只能在于运行时完成,后者显然时可能的,但是可能会导致产生大量的不同的类—可怕的事情。


对此我们考虑一下半篇的主题,装饰者模式。

我们有一个抽象的计算器类:

abstract class Caculator {

	public int add(int x, int y) {
		return x + y;
	}

	public int dec(int x, int y) {
		return add(x, -y);
	}

	public int mul(int x, int y) {
		return x * y;
	}

	public int div(int x, int y) {
		return x / y;
	}

	abstract public int caculate(int x, int y, char operation);
}

该类提供基础的 +,-,x,/四则运算,但是主体的计算函数需要子类去实现。

class SimpleCaculator extends Caculator {

	@Override
	public int caculate(int x, int y, char operation) {
		switch (operation) {
		case '+':
			return add(x, y);
		case '-':
			return dec(x, y);
		case 'x':
			return mul(x, y);
		case '/':
			return div(x, y);
		default:
			break;
		}
		return Integer.MIN_VALUE;
	}
}

我们的简单计算器,实现了根据运算符去判断调用什么函数。

但是这个里面没有实现求余操作啊,我们该怎么办呢?

interface CaculatorWrapper {
	public int mod(int x, int y);
}

class MoreComplexCaculator extends Caculator implements CaculatorWrapper {
	private Caculator caculator = null;

	public MoreComplexCaculator(Caculator caculator) {
		this.caculator = caculator;
	}

	@Override
	public int mod(int x, int y) {
		return caculator.caculate(x, caculator.caculate(caculator.caculate(x, y, '/'), y, 'x'), '-');
	}

	@Override
	public int caculate(int x, int y, char operation) {
		switch (operation) {
		case '%':
			return mod(x, y);
		default:
			return caculate(x, y, operation);
		}
	}
}

利用 mod = x - x / y *y 计算余数

然后我们成功的给该计算器添加了新功能求余。

public class Decorator {
	public static void main(String[] args) {
		Caculator simple = new SimpleCaculator();
		System.out.println(simple.caculate(22, 33, '%'));
		Caculator complex = new MoreComplexCaculator(simple);
		System.out.println(complex.caculate(22, 33, '%'));
	}
}
输出

-2147483648

22


这里我们没有对原先的SimpleCaculator进行任何改动,也没有继承他,我们只是使用其原有的功能,来增加新的功能。


对此我们将上述例子可以总结以下:

你如何组织你的代码使其可以容易的添加基本的或者一些很少用到的 特性,而不是直接不额外的代码写在你的类的内部?

解决方案:
        装饰器模式: 动态地给一个对象添加一些额外的职责或者行为。就增加功能来说, Decorator模式相比生成子类更为灵活。
        装饰器模式提供了改变子类的灵活方案。装饰器模式在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
       当用于一组子类时,装饰器模式更加有用。如果你拥有一族子类(从一个父类派生而来),你需要在与子类独立使用情况下添加额外的特性,你可以使用装饰器模式,以避免代码重复和具体子类数量的增加。


结构:

抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这些对象动态地添加职责。
具体组件角色(ConcreteComponent) :被装饰者,定义一个将要被装饰增加功能的类。可以给这个类的对象添加一些职责
抽象装饰器(Decorator):维持一个指向构件Component对象的实例,并定义一个与抽象组件角色Component接口一致的接口
具体装饰器角色(ConcreteDecorator):向组件添加职责。

按照上例各类角色如下:

抽象组件角色:Caculator类

具体组件对象:SimpleCaculator类

抽象装饰器:CaculatorWrapper接口

具体装饰器类:ComplexCaculator类



效果
装饰模式的特点:
       (1) 装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
  (2) 装饰对象包含一个真实对象的索引(reference)
  (3) 装饰对象接受所有的来自客户端的请求。它把这些请求转发给真实的对象。
  (4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
     Decorator模式至少有两个主要优点和两个缺点:
1) 比静态继承更灵活: 与对象的静态继承(多重继承)相比, Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类。这会产生许多新的类,并且会增加系统的复杂度。此外,为一个特定的Component类提供多个不同的 Decorator类,这就使得你可以对一些职责进行混合和匹配。使用Decorator模式可以很容易地重复添加一个特性。
2) 避免在层次结构高层的类有太多的特征 Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用 Decorator类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能。这样,应用程序不必为不需要的特征付出代价。同时更易于不依赖于 Decorator所扩展(甚至是不可预知的扩展)的类而独立地定义新类型的 Decorator。扩展一个复杂类的时候,很可能会暴露与添加的职责无关的细节。
3) Decorator与它的Component不一样 Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰不应该依赖对象标识。

4) 有许多小对象 采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。




具体实例:我们的IO流包中,很多的流类都是采用了装饰器模式。就比如:

public class FilterInputStream extends InputStream {
 
    protected volatile InputStream in;

    protected FilterInputStream(InputStream in) {
        this.in = in;
    }

    public int read() throws IOException {
        return in.read();
    }

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

    public int read(byte b[], int off, int len) throws IOException {
        return in.read(b, off, len);
    }

    public long skip(long n) throws IOException {
        return in.skip(n);
    }

    public int available() throws IOException {
        return in.available();
    }

    public void close() throws IOException {
        in.close();
    }

    public synchronized void mark(int readlimit) {
        in.mark(readlimit);
    }

    public synchronized void reset() throws IOException {
        in.reset();
    }

    public boolean markSupported() {
        return in.markSupported();
    }
}

BufferedInputStream,DataInputStream,PushbackInputStream 继承FilterInputStream  然后扩充其方法 功能。



在我们的spring中 你可以看到xxxxWrapper这些基本上都算是装饰器模式,就比如:

public interface BeanWrapper extends ConfigurablePropertyAccessor {

	Object getWrappedInstance();

	Class<?> getWrappedClass();

	PropertyDescriptor[] getPropertyDescriptors();

	PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;

	void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);

	int getAutoGrowCollectionLimit();

}
BeanWrapper接口定义了提供一个获得bean 运行时状态的方法接口,以供分析操作该bean。

具体实现类为BeanWrapperImpl





总结:

使用装饰设计模式 不必重写任何已有的功能性代码,而是对某个基于对象应用增量变化。 

Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,
而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。
同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。

以下情况使用Decorator模式
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。




Decorator设计模式和Adapter设计模式相比:

1.虽然Adapter模式也能达到和Decorator模式一样增加功能的效果,但是Decorator设计模式更侧重的是转换接口,使的不相容的接口能够兼容而工作。

2.适配器模式是用新接口来调用原接口,原接口对新系统是不可见或者说不可用的。装饰者模式原封不动的使用原接口,系统对装饰的对象也通过原接口来完成使用。

3.关于其包裹的对象:适配器是知道被适配者的详细情况的(就是那个类或那个接口)。装饰者只知道其接口是什么,至于其具体类型(是基类还是其他派生类)只有在运行期间才知道。




浪涌电流测试仪的工作原理 浪涌电流脉冲形成的开始由同步电路 13 确定,该同步电路 13 发送命令以打开和第二开关 10 和 11,向发生器 14 发送控制命令以生成被测半导体器件 5 的控制信号和参考信号整形器 9 的触发脉冲。电流源的功率输出并联连接,以对流经被测半导体样品的电流求和。此外,使用数字控制扩展了测试仪的功能,能够产生各种形状的电流脉冲,例如梯形电流脉冲,以估计被测晶闸管的导通状态扩展时间。由于晶体管3的栅极是连接的,并且平衡电阻4包含在晶体管3的源中,因此通过每个晶体管3的电流脉冲大致相同,并重复参考信号的形状。 阅读详情

相关推荐

ADC学习(3)——采样电路

第三章 采样电路

夏风喃喃的博客 3万+

C++设计模式——单例模式(Singleton Pattern)

C++设计模式——单例模式(Singleton Pattern) 微信公众号:幼儿园的学霸 目录 文章目录C++设计模式——单例模式(Singleton Pattern)目录定义代码示例懒汉模式线程/内存不安全方式智能指针+双检锁模式和智能指针+call_once模式局部静态变量模式饿汉模式总结参考资料 定义 单例模式顾名思义,保证一个类仅可以有一个实例化对象,并且提供一个可以访问它的全局接口。实现单例模式必须注意一下几点: 单例类只能由一个实例化对象。 单例类必须自己提供一个实例化对象。 单例类必须

leonardohaig的博客 1467

从仿真到实践:两级直接耦合放大电路的静态工作点协同调试指南

本文详细解析了两级直接耦合放大电路的静态工作点协同调试方法,从仿真到实践提供系统指南。重点介绍了Rc2电阻调整技巧、集电极电位测量方法及常见问题排查,帮助工程师解决各级静态工作点相互影响的难题,提升模拟电路设计效率。

weixin_29189373的博客 124

侯捷C++设计模式总结

面向对象设计原则 依赖倒置原则 开放封闭原则 单一职责原则 里氏替换原则 接口隔离原则 优先使用对象组合,而不是类继承 封装变化点 针对接口编程,而不是针对实现编程 剩下的以后再补充 ...

wulalalawu的博客 1002

microblaze之Video Processing Subsystem调试误区

内容:总结video processing subsystem调试中遇到的问题,以及在解决问题中的思路方法论,引为前车之鉴。 1,我的目的是希望采用vps中的scaler模块对图像进行拉伸缩小。IP的配置如下: 2,整个系统的框架图如下,仅比上期的内容增加了scaler模块,如下: 3,查手册,可以知道这个scaler only组件分成了hscale,vscale和GPIO,其中GPIO是控制上下游stream流控设备复位用,暂时忽略。 hscale和vscale的寄存器空间如下,主要关注图

YDY5659150的专栏 3555

ROS下UR+Realsense相机进行手眼标定

手眼标定主要是用来确定相机坐标系和机械臂坐标系之间的转换关系,从而实现后续的抓取等任务。

weixin_42157689的博客 7569

候捷高级设计模式培训小结

上大学时精读过一些侯捷老师的书,基本每重看一遍都感觉有所获。这次能参加这样的一个培训,首先我要感谢我们公司的技术总监Johu Wu 给我这样的一个机会,为了表示感谢我将按他的要求每年精读五本有价值的书,当时他跟我说时我还以为是一件很轻松的事,现在看来要做到还真是不容易! 侯老师对模式的讲解顺序依次是: Template Method -&gt; Abstract Factory -&gt; S...

Tim.Tang's Blog 278

第十二天:Python字典(Dict)详解

字典(Dictionary)是Python中最强大的数据类型之一,它是一种可变的、无序的键值对(key-value)集合。字典中的元素是通过键(key)来存取的,而不是通过偏移量(如列表中的索引)。 字典的核心特性包括: 键值对结构:每个元素由一个键和一个值组成,中间用冒号(:)分隔 无序性:字典中的元素没有固定的顺序(Python 3.7+版本中字典会保持插入顺序,但不应依赖此特性进行顺序操作) 可变性:可以动态地添加、修改或删除键值对 键的唯一性:字典中的键必须是唯一的,如果重复,后面的键值对会覆盖

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 1677

侯捷先生的Design Patterns高级课程

    2003年的下半年,侯捷先生应北京一家企业的邀请来讲授STL课程。那时候我刚到优快云工作,代表优快云接待侯先生,从而有机会在现场聆听侯老师讲授课程。侯先生的授课风格细致清晰,丝丝入扣,一丝不苟。我们在平时学习中难免会留下一些似是而非的地方,经过他的梳理,都能一扫而清,胸中有豁然开朗的感觉。在讲课中,侯老师偶尔会涉及到设计模式的内容,虽然不是重点,但是阐述清晰透彻,令我大感兴趣。设计模式

孟岩 1万+

RT-DETR改进策略【损失函数篇】| 2024 引进Focaler-IoU损失函数 加强边界框回归 (Focaler-DIoU、Focaler-GIoU、Focaler-CIoU等)

本文记录的是改进RT-DETR的损失函数,将其替换成。现有研究通过利用边界框之间的几何关系来提高回归性能,但忽略了困难样本和简单样本分布对边界框回归的影响。不同检测任务中困难样本和简单样本的分布不同,对于简单样本占主导的检测任务,关注简单样本的边界框回归有助于提高检测性能;对于困难样本比例较高的检测任务,需要关注困难样本的边界框回归。,提高检测器在不同检测任务中的性能。实现的。

Limiiiing的博客 1922

Amazon SES 移出沙盒完整指南 & 高通过率模板

AWS SES沙盒模式转正式模式申请指南 申请正式模式需通过AWS审核,常见被拒原因包括邮件用途不清晰、缺少退订机制或发送量不合理。人工申诉需登录AWS Support Center提交服务限额提升请求,填写详细的公司信息、邮件用途及合规措施。 高通过率申诉模板需包含: 公司信息:名称、网址及与AWS的合作情况。 邮件规范:明确类型(交易/营销)、退订链接及退信处理机制。 发送计划:合理预估发送量,确保合规。 关键点:真实信息、用途清晰、退订机制完善、发送量合理。首次被拒可修改后重新提交。

xianyinsuifeng的博客 328

DesignPattern.Ch6.Decorator.Note

装饰模式(Decorator),动态给一些对象添加额外的职责,就增加功能而言,装饰模式比声明子类更加灵活[DP]。 装饰模式使用: 利用SetComponent来对对象进行包装的,这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中的[DEP]。 装饰模式的原型实现: Pattern.Decorator.Pro...

114

QMK键盘固件开发零基础教程(2025全新重制版)

《QMK键盘固件开发零基础教程(2025全新重制版)》是一套专为键盘爱好者和开发者设计的全面教程,旨在帮助用户从零基础快速掌握最新的QMK固件开发技术。教程基于2025年最新的QMK版本(0.19.8+),解决了旧版教程中的诸多问题,如概念不清、步骤缺失和代码过时等。新版教程提供了详细的图解、完整的项目源码以及从环境配置到高级功能开发的全流程指导。此外,教程还涵盖了2024年QMK生态的重大变革,包括键码系统的重构、编译工具链的更新以及Config文件格式的改变等。付费版教程额外提供独家内容,如新特性解析、

Despacito0o的博客 1119

装饰模式Decorator

原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11409608.html 1. 定义动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。 2. 结构图 Component:组件对象的接口,可以给这些对象动态地添加职责。ConcreteComponent:具体的组件对象,实现组件对象接口,通常...

89

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

设计模式的比喻

着楼主的帖子,在心里把GOF DP又过了一遍,感觉这种方式来学习DP很可取,不拘泥于具体而着重于思想。里面的一些内容个人觉得有些地方不太恰当,提出来供参考:创建型模式1、FACTORY—人才市场:以往是要哪个人才,就找哪个人才,效率低,现在有了人才市场,我们只需直接去人才市场挑一个好了;--人市换成猎头公司如何? 2、BUILDER—生产流水线:以前是手工业作坊式的人工单个单个的生产零件然后一步一

§为艺术而技术§ 1255

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

设计模式之门面(Facde)、调停器(Mediator)、装饰器(Decorator)

门面(Facde)、调停器(Mediator)、装饰器(Decorator) 门面模式(Facde) 示意图 用户调用的模块之间的关系错综复杂,使用门面模式来使得调用者调用更加方便直接。 案例 SpringMVC中的DispatcherServlet 把本来需要请求多个接口的业务改成只请求一个接口的业务 调停器(Mediator) 示意图 模块之间错综复杂的调用关系,通过引入一个中间协调者来解耦模式之间的复杂关系。 案例 消息队列 装饰器模式(Decorator) 顾名思义就是给类加一

eddie's Blog 571

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

设计模式Decorator Pattern

装饰器模式:避免子类膨胀,继承的一个替代模式,动态扩展一个实现类的功能。人、衣服:被装饰类和装饰类,随意搭配 package decorater; public interface Person { public void getDress(); } package decorater; public class BlackPerson implements Person{ ...

sinaihalo的博客 180

装饰模式(Decorator)

     装饰模式又名包装模式,是以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。举个例子,比如有一个车(Vehicle)对象, 现在提倡环保,车可以烧各种燃料,如电、天然气、柴油、汽油、氢气等,也可以烧几种燃料的组合,如果氢气和柴油,汽油和电等。如果这样使用继承,就会有很多的子类。这时可以使用装饰模式。     主要角色: 接口或者抽象基类:所有类的统一接口或父类 被装饰对...

jguangyou的专栏 166

设计模式-装饰模式学习笔记

装饰模式(结构型模式) 装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。[DP] 自己的理解:在不对原有类进行修改的情况下动态的对它进行扩展一些功能 优缺点 优点: 满足开闭原则 能够动态的增删功能,比继承更灵活 缺点: 会多出很多小类,增加了程序的复杂性 难以排错(多...

weixin_30363817的博客 118

六 装饰模式(Decorator)——设计模式学习笔记

装饰模式 装饰模式:动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。【DP】 图1 装饰模式类图 Component是定义一个对象接口,可以给这些对象动态地添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator是装饰抽象类,继承Component,从外类来扩展Compon...

weixin_30354675的博客 88

经典的23种设计模式(转载)

URL:http://blog.youkuaiyun.com/starlee/archive/2006/04/05/651689.aspx [img] http://blog.youkuaiyun.com/images/blog_youkuaiyun.com/starlee/178527/o_DP08.jpg[/img] 对于这23种设计模式,我对创建型和结构型还是有一些感悟的。这从我写的学习笔记中就能看出来。之所以这...

天生我材必有用,千金散尽还复来 159

装饰者模式(Decorator)

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最近看设计模式的书,对于每个模式,用C++写了个小例子,加深一下理解。主要参考《大话设计模式》和《设计模式:可复用面向对象软件的基础》两本书。本文介绍装饰模式的实现。        装饰模式:动态

Butterfly_Dreaming的专栏 854

装饰模式的C++实现——设计模式学习(1)

编程目的:。 装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。[DP]

Fan0920的专栏 630

Decorator Pattern

Intent:Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. While reading theGangOfFourbook on C...

weixin_30859423的博客 126

设计模式(十二)-装饰器模式(Decorator Pattern)——装饰边框与被饰物的一致性

装饰器模式(Decorator Pattern)能不断的为对象添加装饰。 Display.java package com.test.dp.Decorator.Sample; //抽象类,用于显示字符串 public abstract class Display { public abstract int getColumns(); // 获取横向字符数

u014378181的博客 485

翻译TIPatterns--太多(Too many)

太多(Too many)享元(Flyweight):太多对象(too many objects)    Flyweidht模式可能让人感到奇怪的一点是: 它(在其它模式的辅助下)是改善性能(performance hack)的一种方法。 通常来说比较好的做法就是简单的把系统里所有东西都弄成对象,但是有时候这样做会使得产生的对象数量非常巨大,这可能会导致系统过于缓慢或者内存耗尽。   

3199
上一篇: [DP]Composite设计模式
下一篇: 教你如何在Github托管代码
HeapStackk
博客等级 码龄12年 11粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值