- 浏览: 12575 次
- 性别:
- 来自: 大连
最近访客 更多访客>>
文章分类
最新评论
-
weishuguangeye:
写的非常好,总结的也非常好!感谢!
初学Java设计模式随记 -- 抽象工厂(Abstract Factory)模式
装饰(Decorator)模式又叫包装器(Wrapper)模式。
1. 用意
动态地给一个对象添加一些额外的职责。
2. 参与者
• 抽象构件(Component):定义一个对象接口,可以给这些对象动态地添加职责。
• 具体构件(Concrete Component):定义一个对象,可以给这个对象添加一些职责。
• 抽象装饰者(Decorator):持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
• 具体装饰者(Concrete Decorator):向组件添加职责。
3.结构
在阎宏的设计模式中,提到“装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方法。”
先来理解装饰模式的用意-----------动态地给一个对象添加一些额外的职责。
所谓动态是说可以在系统运行时(RunTime)动态给对象增加其它职责而不需要修改代码或重新编译;
所谓静态是说必须通过调整代码(DesignTime)才能给对象增加职责,而且系统还需要重新编译;
从具体技术层面来说,对象的组合和继承正好对应于前面的动态和静态
我们应该多使用对象组合来保持系统的运行时扩展性,尽量少使继承,因为继承让程序变得僵硬!
这就是优先使用对象组合,而非类继承(Favor composition over inheritance.)。
再来理解一下“装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方法。”这句话。
Decorator是装饰者模式里非常特殊的一个类,它既继承于Component(IS A关系),又维护一个指向Component实例的引用(HAS A关系),换个角度来说,Decorator跟Component之间,既有动态组合关系又有静态继承关系。
这里为什么要这么来设计?
组合的好处是可以在运行时给对象增加职责,Decorator 有一个(HAS A) Component的目的是让具体装饰者(Concrete Decorator)可以在运行时动态给具体构件(Concrete Component)增加职责,这一点相对来说还比较好理解;
那么Decorator继承于Component的目的是什么?
在这里,继承的目的只有一个,那就是可以统一装饰者和被装饰者的接口,换个角度来说,不管是具体构件(Concrete Component)还是具体装饰者(Concrete Decorator),它们都是 Component,用户代码可以把它们统一看作Component来处理,这样带来的更深一层的好处就是,装饰者对象对被装饰者对象的功能职责扩展对用户代码来说是完全透明的,因为用户代码引用的都是Component,所以就不会因为被装饰者对象在被装饰后,引用它的用户代码发生错误,实际上不会有任何影响,因为装饰前后,用户代码引用的都是Component类型的对象。
装饰者模式通过继承实现统一了装饰者和被装饰者的接口,通过组合获得了在运行时动态扩展被装饰者对象的能力。
还是通过例子来说明:
首先,不使用装饰模式,想想怎么实现下面的需求。
1.还是以买汽车为例---顾客要去汽车代理商买汽车,代理商提供了一些服务,刚开始是一些售后维修服务;
2.后来,还提供了零部件供应的服务;然后,又提供了一些咨询服务(代理商解答顾客买车前的一些疑问);最后,又为客户提供了车险的服务。
3.如果代理商需要根据情况,提供不同的服务组合。
(这里就不写代码来实现了)
大多数情况下,都会使用继承,这样,主要会有下面的问题:
1. 系统的扩展性很差;
2. 当需要提供不同的服务组合时,需要创建大量的类,造成类爆炸;
那么,看看装饰模式是怎么实现上面的需求的。Java代码如下:
抽象构件(Component): 汽车销售商
/** * 抽象构件(Component) * * 汽车销售商 */ public interface CarSeller { /* * 销售汽车 */ String sellCars(); }
具体构件(Concrete Component):奥迪汽车经销商
/** * 具体构件(Concrete Component) * * 奥迪汽车经销商 */ public class AudiCarAgency implements CarSeller { /* * 销售奥迪汽车 */ public String sellCars() { System.out.println("销售奥迪汽车"); return "奥迪汽车"; } }
抽象装饰者(Decorator):提供服务的奥迪销售商
/** * 抽象装饰者(Decorator) * * 提供服务的奥迪销售商 */ public class AudiCarAgencyWithServices implements CarSeller { private CarSeller carSeller = null; /* * 构造函数 */ public AudiCarAgencyWithServices(CarSeller carSeller) { this.carSeller = carSeller; } /* * 装饰 * @see myDecoratorPattern.sellCars.CarSeller#sellCars() */ public String sellCars() { String carName = null; carName = carSeller.sellCars(); return carName; } }
具体装饰者(Concrete Decorator):提供维修服务的奥迪销售商
/** * 具体装饰者(Concrete Decorator) * * 提供维修服务的奥迪销售商 * */ public class AudiCarAgencyWithMaintenance extends AudiCarAgencyWithServices { /* * 构造函数 */ public AudiCarAgencyWithMaintenance(CarSeller carSeller) { super(carSeller); } /* * 添加了其他的服务 */ public String sellCars(){ String carName = super.sellCars(); System.out.println("提供维修服务"); return carName; } }
具体装饰者(Concrete Decorator):提供零配件供应的奥迪销售商
/** * 具体装饰者(Concrete Decorator) * * 提供零配件供应的奥迪销售商 * */ public class AudiCarAgencyWithSparepart extends AudiCarAgencyWithServices { /* * 构造函数 */ public AudiCarAgencyWithSparepart(CarSeller carSeller) { super(carSeller); } /* * 添加了其他的服务 */ public String sellCars(){ String carName = super.sellCars(); System.out.println("提供零配件供应"); return carName; } }
具体装饰者(Concrete Decorator):提供售前咨询服务的奥迪销售商
/** * 具体装饰者(Concrete Decorator) * * 提供售前咨询服务的奥迪销售商 * */ public class AudiCarAgencyWithConsultation extends AudiCarAgencyWithServices { /* * 构造函数 */ public AudiCarAgencyWithConsultation(CarSeller carSeller){ super(carSeller); } /* * 添加了其他的服务 */ public String sellCars() { System.out.println("提供了售前咨询服务"); return super.sellCars(); } }
具体装饰者(Concrete Decorator):提供车险服务的奥迪销售商
/** * 具体装饰者(Concrete Decorator) * * 提供车险服务的奥迪销售商 * */ public class AudiCarAgencyWithInsurance extends AudiCarAgencyWithServices { /* * 构造函数 */ public AudiCarAgencyWithInsurance(CarSeller carSeller) { super(carSeller); } /* * 添加了其他的服务 */ public String sellCars(){ String carName = super.sellCars(); System.out.println("提供车险的购买"); return carName; } }
结构如下:
客户端的调用:
public class Customer { public static void main(String[] args){ String car = null; System.out.println("--------------只卖车,没有服务------------------"); // 汽车经销商 CarSeller carSeller = new AudiCarAgency(); car = carSeller.sellCars(); System.out.println("买到了" + car); System.out.println("--------------第一种组合-维修服务------------------"); // 提供了维修服务 CarSeller carSellerWithMaintenance = new AudiCarAgencyWithMaintenance(carSeller); car = carSellerWithMaintenance.sellCars(); System.out.println("买到了" + car); System.out.println("--------------第二种组合-添加了零部件供应服务---------"); // 提供了零部件供应 CarSeller carSellerWithSparepart = new AudiCarAgencyWithSparepart(carSellerWithMaintenance); car = carSellerWithSparepart.sellCars(); System.out.println("买到了" + car); System.out.println("--------------第三种组合-添加了咨询服务--------------"); // 提供了咨询服务 CarSeller carSellerWithConsultation = new AudiCarAgencyWithConsultation(carSellerWithSparepart); car = carSellerWithConsultation.sellCars(); System.out.println("买到了" + car); System.out.println("--------------第四种组合-添加了车险服务--------------"); // 提供了车险 CarSeller carSellerWithInsurance = new AudiCarAgencyWithInsurance(carSellerWithConsultation); car = carSellerWithInsurance.sellCars(); System.out.println("买到了" + car); System.out.println("#########################################"); // 还可以有其他的组合方式 System.out.println("还可以尝试其他形式自由的组合。。。。。。"); } }
运行结果:
--------------只卖车,没有服务------------------ 销售奥迪汽车 买到了奥迪汽车 --------------第一种组合-维修服务------------------ 销售奥迪汽车 提供维修服务 买到了奥迪汽车 --------------第二种组合-添加了零部件供应服务--------- 销售奥迪汽车 提供维修服务 提供零配件供应 买到了奥迪汽车 --------------第三种组合-添加了咨询服务-------------- 提供了售前咨询服务 销售奥迪汽车 提供维修服务 提供零配件供应 买到了奥迪汽车 --------------第四种组合-添加了车险服务-------------- 提供了售前咨询服务 销售奥迪汽车 提供维修服务 提供零配件供应 提供车险的购买 买到了奥迪汽车 ######################################### 还可以尝试其他形式自由的组合。。。。。。
可以看到使用装饰模式,有如下优点:
1. 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以使用很少的类,创造出很多不同的行为组合。
以上内容部分参照自阎宏的《Java与模式》以及来杯咖啡-装饰者模式(Decorator)实例应用详解
如果仔细观察装饰模式的调用(例如:第二种组合-添加了零部件供应服务)时,感觉装饰模式和代理模式的作用好像一样(都给一个对象添加了额外的功能);甚至,如果比较这两个模式的结构时,好像也没什么差别。那么,它们到底有什么区别呢?
首先,它们的用意是不同的:
代理模式是 控制 对一个对象的访问。
装饰模式是 增加 一个类的职责(功能)。
单从它们的结构来看,
使用代理模式时,在访问对象之前或之后也可以添加一些额外的操作,这一点,装饰模式和代理模式差不多,甚至可以说,这两个模式是一样的,都为一个类(一个对象)添加了其他功能。
但如果仔细体会“控制”和“增加”这两个词汇,可能会发现,
代理模式中,所添加的额外的操作,往往为了确定被访问对象者是否能被访问。
而在装饰模式中,增加的这些功能,不会影响原有对象的操作,被装饰的对象一定会被访问的。
发表评论
-
初学Java设计模式随记 -- 适配器(Adpater)模式
2011-01-10 10:10 0适配器(Adpater)模式 1.用意: 将一个类的 ... -
初学Java设计模式随记 -- 代理(Proxy)模式之动态代理(Dynamic Proxy)
2010-12-28 20:51 950什么是动态代理? 被代理的对象(真实主题(RealSu ... -
初学Java设计模式随记 -- 代理(Proxy)模式之静态代理(Static Proxy)
2010-12-28 20:51 886代理(Proxy)模式 1. 用意:为其他对象提供一种 ... -
初学Java设计模式随记 -- 原型(Prototype)模式
2010-12-11 16:44 929原型(Prototype)模式也有 ... -
初学Java设计模式随记 -- 单例(Singleton)模式
2010-12-01 22:19 740本篇内容主要摘取自GoF的设计模式和阎宏的《Java与模式》 ... -
预览文章: 初学Java设计模式随记 -- 建造者(BUILDER)模式
2010-11-30 22:49 780建造者(BUILDER)模式又叫生成器(BUILDER) ... -
初学Java设计模式随记 -- 抽象工厂(Abstract Factory)模式
2010-11-20 22:44 1138抽象工厂(Abstract Factory ... -
初学Java设计模式随记 -- 工厂方法(Factory Method)模式
2010-11-17 23:32 854工厂方法(Factory Method)模式,又叫做虚拟构造子 ... -
初学Java设计模式随记 -- 简单工厂模式(Simple Factory Pattern)
2010-11-17 23:32 1199简单工厂(Simple Factory)模式: 又称静态工厂方 ... -
初学Java设计模式随记 -- 工厂模式(Factory Pattern) 续
2010-11-14 21:03 850利用工厂模式可以将对象的创建过程和使用进行分离(也就是解藕), ... -
初学Java设计模式随记 -- 工厂模式(Factory Pattern)
2010-11-10 13:13 882在阎宏《JAVA与设计 ... -
初学Java设计模式随记 -- GOF 设计模式分类
2010-11-05 09:42 816以下摘自《GOF设计模式 可复用面向对象软件的基础》中文 ... -
初学Java设计模式随记 -- 带着疑问学习设计模式
2010-11-04 00:07 875最近在学习设计模式时,发现总是会有一些疑问,有的能找到答案,有 ... -
初学Java设计模式随记 -- 为什么学习设计模式
2010-11-03 21:26 697这段时间在学习设计模 ...
相关推荐
NULL 博文链接:https://andycbluo.iteye.com/blog/2269582
Java.util包常用接口
java随记
OleDbDataAdapter 不会自动生成,为了使对 DataSet 所作的更改和相关联的数据源协调起来所必须的 SQL 语句。但是,如果设置了 OleDbDataAdapter 的 SelectCommand 属性,那么就可以创建 OleDbCommandBuilder 对象,来...
JSP PDF打印 随记 复杂模板设计
数据分级存储及访问方式设计方案研究随记.docx数据分级存储及访问方式设计方案研究随记.docx
c# 随记.docx
NULL 博文链接:https://lobin.iteye.com/blog/2365756
网络原理随记.pdf
互联网公司实习日记随记参考.pdf互联网公司实习日记随记参考.pdf互联网公司实习日记随记参考.pdf互联网公司实习日记随记参考.pdf互联网公司实习日记随记参考.pdf互联网公司实习日记随记参考.pdf
三天不读书&智商输给猪-世界读书日ppt随记PPT模板.pptx
linux net 管理随记,留着个人备忘
生产不重复19位随机数,测试1000000数据没重复
用户信息手账信息 第一章 用户信息信息设计 2 用户信息信息设计昵称限制:1~18位(非必需、如果没有输入则自动生成一个随机字符串6~12位、特殊符号非法)
一款很好用的java反编译软件,直接下载就可以使用,无需安装软件
学习c++过程中的一些知识点随记,我感觉重要的就稍微记了一下,比较简略,但是快速的阅读的话可以提醒自己想起那一部分的知识点。在复习c++知识点的时候,有些帮助。
Unity 随记1
git随记 git
面试随记???随时更新
重点小学生寒假记随记大全.doc