博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式总结篇系列:装饰器模式(Decorator)
阅读量:6106 次
发布时间:2019-06-21

本文共 4167 字,大约阅读时间需要 13 分钟。

在面向对象设计过程中,经常会遇到需要对现有的类的功能进行扩展,通常我们可以采用继承的方式。例如老罗最近在做手机,一开始需要定义手机所应具有的功能:

1 interface Phone{2     3     public void tel();4     5     public void sms();6     7 }

在此,为简单起见,只是定义了接打电话和收发短信功能。

然后,老罗开始造手机,经过两年艰苦努力,第一代手机T1终于面世了,很高兴的开了发布会,反响还不错。

1 class T1 implements Phone{ 2  3     @Override 4     public void tel() { 5         System.out.println("可以实现基本的接打电话"); 6     } 7  8     @Override 9     public void sms() {10         System.out.println("可以实现基本的收发短信功能");11     }12     13 }

T1面世了,当然,只有不短的追求才有更大的进步的,在进一步的努力后,新一代的T2可以在T1的基础上实现安装Android软件的功能了。通常情况下,我们可能进行如下定义:

1 class T2 extends T1{2     3     public void installApk(){4         System.out.println("可以安装Android软件了");5     }6     7 }

显然,采取了继承的方式,T2在T1的基础上新增了自己所具有的更多功能——可以安装Android软件。这是一个进步。

又过了一段时间,老罗想出做手机不仅仅需要满足这些基本的功能,还应该最大程度上的最好用户体验,于是,目前最快的闪拍被想到了,此功能被加入到了最新一代的T3中。

1 class T3 extends T2{2     3     public void fastestPhoto(){4         System.out.println("可以实现目前最快的闪拍");5     }6     7 }

自然的,我们首先想到的还是通过继承的方式,在继承第2代基础上扩充了T3的功能。

当然,这是一件相当值得庆贺的事情。现在T1、T2、T3都面向市场推出了。由于市场需求较大,每一代的手机都在不断的制造中。现在有一个新的需求出来了,电信的用户反馈,这么手机都不支持电信卡,怎么办?

于是,老罗为了满足电信用户,急需在T2上推出相应的电信手机,那么现在怎么办呢?第一个想到的可能是修改T2类:

1 class T2 extends T1 { 2  3     public void installApk() { 4         System.out.println("可以安装Android软件了"); 5     } 6  7     @Override 8     public void tel() { 9         supportDx();10         System.out.println("可以实现基本的接打电话");11     }12 13     @Override14     public void sms() {15         supportDx();16         System.out.println("可以实现基本的收发短信功能");17     }18 19     public void supportDx() {20         System.out.println("可以支持电信用户了");21     }22 23 }

现在问题就出来了,由于继承关系的存在,虽然表面上只是修改了T2类,实际上其所有的子类都间接的被修改了。那么现在又有两个选择,要么修改其所有子类,这肯定不实际,要么不修改T2类,以免带来不必要的T2修改后对其所有子类的影响,但为了满足需求,可能得继承T2类新定义一个新的类,这样会导致类的无线膨胀问题(因为这种需求是不可预估的),那么有没有什么好的解决方案呢?

于是,基本包装/装饰而不是继承来实现此类场景的类的设计是一个不错的选择。由此带来的设计模式称之为"装饰模式"。

为了给一个现有的类增加一些新的功能,而不引其原来类的修改,用装饰模式去代替继承模式,要求装饰类和被装饰类实现同一接口,装饰对象有被装饰对象的实例。

那么我们具体看一下在上面场景中使用装饰模式如何设计类。

1 class T2 implements Phone { 2  3     private Phone phone; 4  5     public T2(Phone phone) { 6         this.phone = phone; 7     } 8  9     public void installApk() {10         System.out.println("可以安装Android软件了");11     }12 13     @Override14     public void tel() {15         phone.tel();16     }17 18     @Override19     public void sms() {20         phone.tel();21     }22 23 }

T3类设计与之类似,那么现在T2需要支持电信用户呢?这是直接修改T2类即可,并且对其他类(因为它没有子类之说了)是没有影响的。

1 class T2 implements Phone { 2  3     private Phone phone; 4  5     public T2(Phone phone) { 6         this.phone = phone; 7     } 8  9     public void installApk() {10         System.out.println("可以安装Android软件了");11     }12 13     @Override14     public void tel() {15         this.supportDx();16         phone.tel();17     }18 19     @Override20     public void sms() {21         this.supportDx();22         phone.tel();23     }24 25     public void supportDx() {26         System.out.println("可以支持电信用户了");27     }28 29 }

测试:

1 public class DecoratorTest { 2  3     public static void main(String[] args) { 4         Phone t1 = new T1(); 5         Phone t2 = new T2(t1); 6         t2.tel(); 7         t2.sms(); 8     } 9 10 }

怎么样,利用装饰模式设计类代替原本的继承是不是优势马上显示出来了,可能有人会说,这样设计会违背T2的愿意,可能有些T2本没必要支持电信用户,哦,确实如此,那好办啊,在创建的时候T2对象的时候加一个参数去控制就可以了啊。大概如下:

1 class T2 implements Phone { 2  3     private Phone phone; 4     private boolean isSupportDx; 5  6     public T2(Phone phone, boolean isSupportDx) { 7         this.phone = phone; 8         this.isSupportDx = isSupportDx; 9     }10 11     public void installApk() {12         System.out.println("可以安装Android软件了");13     }14 15     @Override16     public void tel() {17         this.supportDx();18         phone.tel();19     }20 21     @Override22     public void sms() {23         this.supportDx();24         phone.tel();25     }26 27     public void supportDx() {28         if (isSupportDx) {29             System.out.println("可以支持电信用户了");30         }31     }32 33 }
1 public class DecoratorTest { 2  3     public static void main(String[] args) { 4         Phone t1 = new T1(); 5         Phone t2 = new T2(t1, true); // Phone t2 = new T2(t1, false); 6         t2.tel(); 7         t2.sms(); 8     } 9 10 }

 怎么样?装饰模式还是不错的吧,Java IO中的包装流都是采用装饰模式实现的哦。。

 

转载地址:http://njhza.baihongyu.com/

你可能感兴趣的文章
Emulator 29.0.4 Canary 发布,Android 模拟器
查看>>
我们不再需要 Chrome?
查看>>
WordPress 主题开发商将客户当肉鸡,向对手发起 DDoS 攻击
查看>>
一周见闻_v2
查看>>
Django 搭建CMDB系统完整[12](软件资产、厂商)
查看>>
在excel中,链接网站
查看>>
Android 自定义ViewGroup(一)
查看>>
Android项目实战(二十):浅谈ListView悬浮头部展现效果
查看>>
为什么我要放弃javaScript数据结构与算法(第四章)—— 队列
查看>>
利用Android自带的CountDownTimer实现手机验证码倒计时
查看>>
NGINX功能详解
查看>>
程序员被聘用的13个开发技能
查看>>
区块链开发公司谈区块链能源的机遇
查看>>
INSTALL_FAILED_NO_MATCHING_ABIS 的解决办法
查看>>
使用Kafka Manager管理Kafka集群
查看>>
PM2 使用介绍
查看>>
友盟开放日抢先看:数据解读行业趋势
查看>>
便宜就没好货吗?PopUp Viewer头显可能是个例外
查看>>
ApiBoot 0.1.1.RELEASE 版本发布!!!
查看>>
开源 | 蚂蚁金服分布式中间件开源第三弹: 下一代微服务SOFAMesh
查看>>