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

 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)的更多相关文章

  1. 设计模式(八)装饰器模式Decorator(结构型)

    设计模式(八)装饰器模式Decorator(结构型) 1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法 ...

  2. 【PHP设计模式 09_ZhuangShiQi.php】装饰器模式 (decorator)

    <?php /** * [装饰器模式 (decorator)] * 有时候发布一篇文章需要经过很多人手,层层处理 */ header("Content-type: text/html; ...

  3. 设计模式(三)——装饰器模式(Decorator Pattern)

    发现太过于刻意按照计划来写博客,有点不实际,刚好最近在一个网课上复习AOP的知识,讲到了装饰器模式和代理模式,顺便复习总结一下. 首先了解一下装饰器模式,从名字里面可以看出来,装饰器模式就类似于房子装 ...

  4. php设计模式课程---7、装饰器模式如何使用

    php设计模式课程---7.装饰器模式如何使用 一.总结 一句话总结: 装饰器的核心是获取了文章类整个类,而不是获取了文章内容,有了这个文章类,我想给你加多少装饰就给你加多少装饰(将文章这个类封装进去 ...

  5. 装饰器模式-Decorator(Java实现)

    装饰器模式-Decorator(Java实现) 装饰器模式允许向一个现有的对象添加新的功能, 同时又不改变其结构. 其中 "现有对象"在本文中是StringDisplay类. 添加 ...

  6. Java设计模式系列-装饰器模式

    原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...

  7. 说说设计模式~装饰器模式(Decorator)~多功能消息组件的实现

    返回目录 为何要设计多功能消息组件 之前写过一篇装饰器模式的文章,感觉不够深入,这次的例子是实现项目中遇到的,所以把它拿出来,再写写,之前也写过消息组件的文章,主要采用了策略模式实现的,即每个项目可以 ...

  8. 装饰器模式 Decorator 结构型 设计模式 (十)

    引子           现实世界的装饰器模式 大家应该都吃过手抓饼,本文装饰器模式以手抓饼为模型展开简介 "老板,来一个手抓饼,  加个培根,  加个鸡蛋,多少钱?" 这句话会不 ...

  9. 设计模式学习心得<装饰器模式 Decorator>

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装 ...

  10. 23种设计模式之装饰器模式(Decorator Pattern)

    装饰器模式(Decorator Pattern) 允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包 ...

随机推荐

  1. nginx.conf 中php-ftp配置

    location ~ .php$ { root /home/www; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_par ...

  2. HTML/CSS实现的一个列表页

    又到休息日,白天没事跟朋友去逛逛街,侃大山,晚上了,上网无趣,于是就想起该练练了, 这次是做了一个页面,最上面是一个banner 用到了一个jQuery的逻辑判断当banner初始top值小于wind ...

  3. java课程之团队开发冲刺阶段1.6

    一.总结昨天进度 1.依照视频学习了sqlite,但是由于视频的不完整性导致并不知道代码的实际效果怎么样. 二.遇到的问题 1.依据上一条,在date目录下date文件夹中,的确发现了数据库的文件,但 ...

  4. 手动安装OpenCV下的IPP加速库

    写在前面 安装opencv的时候,往往会卡在这里: IPPICV: Download: ippicv_2019_lnx_intel64_general_20180723.tgz 其实就是墙的原因,然后 ...

  5. python从入门到实践-8章函数

    #!/user/bin/env python# -*- coding:utf-8 -*- # 给形参指定默认值时,等号两边不要有空格 def function_name("parameter ...

  6. DB2 数据库的安装配置及监控

    一.DB2简介 IBM公司研制的一种关系型数据库系统.DB2主要应用于大型应用系统,具有较好的可伸缩性,可支持从大型机到单用户环境,应用于OS/2.Windows等平台下. DB2提供了高层次的数据利 ...

  7. DCOS实践分享(5):Open DCOS深入分析

    2016/05/18(三) 09:30 OpenDC/OS研討會暨工作坊 指導單位:經濟部.科技部 主辦單位:工業技術研究院.Linker Networks 協辦單位:Microsoft.資通訊產業聯 ...

  8. 通过net time同步电脑时间

    net use \\192.168.1.112\ipc$ admin /user:admin #第一个admin是密码,第二个admin是用户名: net time \\192.168.1.112 / ...

  9. zepto与jquery冲突的解决

    一般是不会把zepto和jquery一起来用的.但有时候要引入一些插件,可能就会遇到这样的问题. jquery noConflict() jquery有一个方法叫noConflict() ,可以把jq ...

  10. proxy_pass根据path路径转发时的"/"问题记录

    在nginx中配置proxy_pass时,如果是按照^~匹配路径时,要注意proxy_pass后的url最后的/.当加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理 ...