设计模式总结篇系列:装饰器模式(Decorator)
在面向对象设计过程中,经常会遇到需要对现有的类的功能进行扩展,通常我们可以采用继承的方式。例如老罗最近在做手机,一开始需要定义手机所应具有的功能:
interface Phone{
public void tel();
public void sms();
}
在此,为简单起见,只是定义了接打电话和收发短信功能。
然后,老罗开始造手机,经过两年艰苦努力,第一代手机T1终于面世了,很高兴的开了发布会,反响还不错。
class T1 implements Phone{
@Override
public void tel() {
System.out.println("可以实现基本的接打电话");
}
@Override
public void sms() {
System.out.println("可以实现基本的收发短信功能");
}
}
T1面世了,当然,只有不短的追求才有更大的进步的,在进一步的努力后,新一代的T2可以在T1的基础上实现安装Android软件的功能了。通常情况下,我们可能进行如下定义:
class T2 extends T1{
public void installApk(){
System.out.println("可以安装Android软件了");
}
}
显然,采取了继承的方式,T2在T1的基础上新增了自己所具有的更多功能——可以安装Android软件。这是一个进步。
又过了一段时间,老罗想出做手机不仅仅需要满足这些基本的功能,还应该最大程度上的最好用户体验,于是,目前最快的闪拍被想到了,此功能被加入到了最新一代的T3中。
class T3 extends T2{
public void fastestPhoto(){
System.out.println("可以实现目前最快的闪拍");
}
}
自然的,我们首先想到的还是通过继承的方式,在继承第2代基础上扩充了T3的功能。
当然,这是一件相当值得庆贺的事情。现在T1、T2、T3都面向市场推出了。由于市场需求较大,每一代的手机都在不断的制造中。现在有一个新的需求出来了,电信的用户反馈,这么手机都不支持电信卡,怎么办?
于是,老罗为了满足电信用户,急需在T2上推出相应的电信手机,那么现在怎么办呢?第一个想到的可能是修改T2类:
class T2 extends T1 {
public void installApk() {
System.out.println("可以安装Android软件了");
}
@Override
public void tel() {
supportDx();
System.out.println("可以实现基本的接打电话");
}
@Override
public void sms() {
supportDx();
System.out.println("可以实现基本的收发短信功能");
}
public void supportDx() {
System.out.println("可以支持电信用户了");
}
}
现在问题就出来了,由于继承关系的存在,虽然表面上只是修改了T2类,实际上其所有的子类都间接的被修改了。那么现在又有两个选择,要么修改其所有子类,这肯定不实际,要么不修改T2类,以免带来不必要的T2修改后对其所有子类的影响,但为了满足需求,可能得继承T2类新定义一个新的类,这样会导致类的无线膨胀问题(因为这种需求是不可预估的),那么有没有什么好的解决方案呢?
于是,基本包装/装饰而不是继承来实现此类场景的类的设计是一个不错的选择。由此带来的设计模式称之为"装饰模式"。
为了给一个现有的类增加一些新的功能,而不引其原来类的修改,用装饰模式去代替继承模式,要求装饰类和被装饰类实现同一接口,装饰对象有被装饰对象的实例。
那么我们具体看一下在上面场景中使用装饰模式如何设计类。
class T2 implements Phone {
private Phone phone;
public T2(Phone phone) {
this.phone = phone;
}
public void installApk() {
System.out.println("可以安装Android软件了");
}
@Override
public void tel() {
phone.tel();
}
@Override
public void sms() {
phone.tel();
}
}
T3类设计与之类似,那么现在T2需要支持电信用户呢?这是直接修改T2类即可,并且对其他类(因为它没有子类之说了)是没有影响的。
class T2 implements Phone {
private Phone phone;
public T2(Phone phone) {
this.phone = phone;
}
public void installApk() {
System.out.println("可以安装Android软件了");
}
@Override
public void tel() {
this.supportDx();
phone.tel();
}
@Override
public void sms() {
this.supportDx();
phone.tel();
}
public void supportDx() {
System.out.println("可以支持电信用户了");
}
}
测试:
public class DecoratorTest {
public static void main(String[] args) {
Phone t1 = new T1();
Phone t2 = new T2(t1);
t2.tel();
t2.sms();
}
}
怎么样,利用装饰模式设计类代替原本的继承是不是优势马上显示出来了,可能有人会说,这样设计会违背T2的愿意,可能有些T2本没必要支持电信用户,哦,确实如此,那好办啊,在创建的时候T2对象的时候加一个参数去控制就可以了啊。大概如下:
class T2 implements Phone {
private Phone phone;
private boolean isSupportDx;
public T2(Phone phone, boolean isSupportDx) {
this.phone = phone;
this.isSupportDx = isSupportDx;
}
public void installApk() {
System.out.println("可以安装Android软件了");
}
@Override
public void tel() {
this.supportDx();
phone.tel();
}
@Override
public void sms() {
this.supportDx();
phone.tel();
}
public void supportDx() {
if (isSupportDx) {
System.out.println("可以支持电信用户了");
}
}
}
public class DecoratorTest {
public static void main(String[] args) {
Phone t1 = new T1();
Phone t2 = new T2(t1, true); // Phone t2 = new T2(t1, false);
t2.tel();
t2.sms();
}
}
怎么样?装饰模式还是不错的吧,Java IO中的包装流都是采用装饰模式实现的哦。。
设计模式总结篇系列:装饰器模式(Decorator)的更多相关文章
- 设计模式(八)装饰器模式Decorator(结构型)
设计模式(八)装饰器模式Decorator(结构型) 1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法 ...
- 【PHP设计模式 09_ZhuangShiQi.php】装饰器模式 (decorator)
<?php /** * [装饰器模式 (decorator)] * 有时候发布一篇文章需要经过很多人手,层层处理 */ header("Content-type: text/html; ...
- 设计模式(三)——装饰器模式(Decorator Pattern)
发现太过于刻意按照计划来写博客,有点不实际,刚好最近在一个网课上复习AOP的知识,讲到了装饰器模式和代理模式,顺便复习总结一下. 首先了解一下装饰器模式,从名字里面可以看出来,装饰器模式就类似于房子装 ...
- php设计模式课程---7、装饰器模式如何使用
php设计模式课程---7.装饰器模式如何使用 一.总结 一句话总结: 装饰器的核心是获取了文章类整个类,而不是获取了文章内容,有了这个文章类,我想给你加多少装饰就给你加多少装饰(将文章这个类封装进去 ...
- 装饰器模式-Decorator(Java实现)
装饰器模式-Decorator(Java实现) 装饰器模式允许向一个现有的对象添加新的功能, 同时又不改变其结构. 其中 "现有对象"在本文中是StringDisplay类. 添加 ...
- Java设计模式系列-装饰器模式
原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...
- 说说设计模式~装饰器模式(Decorator)~多功能消息组件的实现
返回目录 为何要设计多功能消息组件 之前写过一篇装饰器模式的文章,感觉不够深入,这次的例子是实现项目中遇到的,所以把它拿出来,再写写,之前也写过消息组件的文章,主要采用了策略模式实现的,即每个项目可以 ...
- 装饰器模式 Decorator 结构型 设计模式 (十)
引子 现实世界的装饰器模式 大家应该都吃过手抓饼,本文装饰器模式以手抓饼为模型展开简介 "老板,来一个手抓饼, 加个培根, 加个鸡蛋,多少钱?" 这句话会不 ...
- 设计模式学习心得<装饰器模式 Decorator>
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装 ...
- 23种设计模式之装饰器模式(Decorator Pattern)
装饰器模式(Decorator Pattern) 允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包 ...
随机推荐
- json字符串的拼接
关于json字符串的解析与拼接,第一次接触,留下个笔记了.......解析,是改的代码,拼接是纯的,解析就不说了,笔记一下拼接了 关于解析主要分三部分,一个是第一层处理,一个是第二层处理,一个是进行& ...
- go-设计思想
1, 围绕 简单 这一核心的设计 隐式接口,切片, 类的弱化,强制用组合 简洁高效的并发 弱化的指针 err 判定,先判错的习俗. 2, 有自己的坚持,不盲目攀比 比优点比不过很多语言,没C快,没ja ...
- C# 异步编程之 Task 的使用
(说明:随笔内容为学习task的笔记,资料来源:https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?redi ...
- web 基础设置
1.设置代码格式为UTF-8 2.运行jsp文档 3.设置自己喜欢的浏览器运行,设置为默认的 找到自己的浏览器位置 点ok Name是名字的意思 为这个浏览器娶一个名字 是什么浏览器就写什么名字 4. ...
- DIV滚动条滚动到指定位置(jquery的position()与offset()方法区别小记)
相对浏览器,将指定div滚到到指定位置,其用法如下 $("html,body").animate({scrollTop: $(obj).offset().top},speed); ...
- 自己封装element-ui树组件的过滤
前言:vue开发项目时用到了element-ui的树组件,但是发现一执行过滤事件,树就全部都展开了,为了解决这个问题,只能自己先过滤数剧,再赋值给树组件的data,就避免了一上来全部展开的尴尬. 一. ...
- jenkins配置演示
构建代码的几个名词: make:linux或者windows最原始的编译工具,在Linux下编译程序常用make,windows下对应的工具为nmake.它负责组织构建的过程,负责指挥编译器如何编译, ...
- 电子科技大学实验中学PK赛(二)比赛题解
比赛地址:http://qscoj.cn/contest/27/ A题 FIFA强化 分析:这个题目要求说的比较明显,用几个if判断一下就好了.不要一判断完就输出,最好用一个ans储存下答案.输出答案 ...
- FFmpeg 结构体学习(六): AVCodecContext 分析
在上文FFmpeg 结构体学习(五): AVCodec 分析我们学习了AVCodec结构体的相关内容.本文,我们将讲述一下AVCodecContext. AVCodecContext是包含变量较多的结 ...
- java中的堆,栈和方法区(转)
来源:https://www.cnblogs.com/iliuyuet/p/5603618.html https://blog.csdn.net/lin542405822/article/detail ...