面向对象的设计模式(二)——Decorator模式
来源:互联网 发布:centos6.5 yum安装 编辑:程序博客网 时间:2024/06/06 07:34
(二)“单一职责”模式
在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键就是划清责任。
1. Decorator 装饰模式
◆ 动机:
在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。
如何使“对象功能的扩展”能够根据需要来动态实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?
首先,用代码举一个例子,这是一个操作数据流的类:
//业务操作abstract class Stream { public abstract char read(int number); public abstract void seek(int position); public abstract void write(char data);}//主体类class FileStream extends Stream { //读文件流 @Override public char read(int number){ //*********** } //定位文件流 @Override public void seek(int position){ //*********** } //写文件流 @Override public void write(char data){ //*********** }}class NetworkStream extends Stream { //读文件流 @Override public char read(int number){ //########### } //定位文件流 @Override public void seek(int position){ //########### } //写文件流 @Override public void write(char data){ //########### }}class MemoryStream extends Stream { //读文件流 @Override public char read(int number){ //@@@@@@@@@@@ } //定位文件流 @Override public void seek(int position){ //@@@@@@@@@@@ } //写文件流 @Override public void write(char data){ //@@@@@@@@@@@ }}//扩展操作class CryptoFileStream extends FileStream { @Override public char read(int number) { //额外的加密操作... //读文件流 super.read(number); } @Override public void seek(int position) { //额外的加密操作... //定位文件流 super.seek(position); //额外的加密操作... } //写内存流 @Override public void write(char data) { //额外的加密操作... //写文件流 super.write(data); //额外的加密操作... }}class CryptoNetworkStream extends NetworkStream { @Override public char read(int number) { //额外的加密操作... //读网络流 super.read(number); } @Override public void seek(int position) { //额外的加密操作... //定位网络流 super.seek(position); //额外的加密操作... } @Override public void write(char data) { //额外的加密操作... //写网络流 super.write(data); //额外的加密操作... }}class CryptoMemoryStream extends MemoryStream { @Override public char read(int number) { //额外的加密操作... //读内存流 super.read(number); } @Override public void seek(int position) { //额外的加密操作... //定位内存流 super.seek(position); //额外的加密操作... } //写内存流 @Override public void write(char data) { //额外的加密操作... //写内存流 super.write(data); //额外的加密操作... }}class BufferedFileStream extends FileStream {}class BufferedNetworkStream extends NetworkStream {}class BufferedMemoryStream extends MemoryStream {}class CryptoBufferedFileStream extends FileStream { @Override public char read(int number) { //额外的加密操作... //额外的缓冲操作... //读文件流 super.read(number); //额外的加密操作... //额外的缓冲操作... } @Override public void seek(int position) { //额外的加密操作... //额外的缓冲操作... //定位文件流 super.seek(position); //额外的加密操作... //额外的缓冲操作... } @Override public void write(char data) { //额外的加密操作... //额外的缓冲操作... //写文件流 super.write(data); //额外的加密操作... //额外的缓冲操作... }}class Client { public static void main(String args[]) { //编译时装配 CryptoFileStream fs1 = new CryptoFileStream(); BufferedFileStream fs2 = new BufferedFileStream(); CryptoBufferedFileStream fs3 = new CryptoBufferedFileStream(); }}代码的结构逻辑如下图,这样的数据机构会生成很多很多子类。注意,crypto、Bufferde这些方法是要在FileStream、NetwodStream等对象的基础上才能实现的。FileStream这些类叫做“主体类”,CryptoFileStream这些类叫做“扩展类”,
利用Decorator模式进行优化,优化后代码如下:
//业务操作abstract class Stream { public abstract char read(int number); public abstract void seek(int position); public abstract void write(char data);}//主体类class FileStream extends Stream { //读文件流 @Override public char read(int number){ //*********** } //定位文件流 @Override public void seek(int position){ //*********** } //写文件流 @Override public void write(char data){ //*********** }}class NetworkStream extends Stream { //读文件流 @Override public char read(int number){ //########### } //定位文件流 @Override public void seek(int position){ //########### } //写文件流 @Override public void write(char data){ //########### }}class MemoryStream extends Stream { //读文件流 @Override public char read(int number){ //@@@@@@@@@@@ } //定位文件流 @Override public void seek(int position){ //@@@@@@@@@@@ } //写文件流 @Override public void write(char data){ //@@@@@@@@@@@ }}//继承:接口协议class CryptoStream extends Stream { /** * 组合:复用实现 */ Stream s;// s=new FileStream(); s=new NetworkStream(); s=new MemoryStream(); // 在子类中以父类的实例作为一个成员变量,这是典型的decrorator模式 /** * 通过构造函数传递一个具体的类型进来 */ public CryptoStream(Stream s) { this.s=s; } @Override public char read(int number) { //额外的加密操作... //读文件流 s.read(number); } @Override public void seek(int position) { //额外的加密操作... //定位文件流 s.seek(position); //额外的加密操作... } //写内存流 @Override public void write(char data) { //额外的加密操作... //写文件流 s.write(data); //额外的加密操作... }}class BufferedStream extends Stream { Stream s; public BufferedStream(Stream s) { this.s=s; }}class Client { public static void main(String args[]) { //运行时装配 Stream s1=new CryptoStream( new FileStream()); Stream fs2 = new BufferedStream(new FileStream()); Stream fs3 = new CryptoStream(new BufferedStream(new FileStream())); }}这样,Decorator模式基本上已经算完成了,不过我们还可以再进行一个小优化:
//业务操作abstract class Stream { public abstract char read(int number); public abstract void seek(int position); public abstract void write(char data);}//主体类class FileStream extends Stream { //读文件流 @Override public char read(int number){ //*********** } //定位文件流 @Override public void seek(int position){ //*********** } //写文件流 @Override public void write(char data){ //*********** }}class NetworkStream extends Stream { //读文件流 @Override public char read(int number){ //########### } //定位文件流 @Override public void seek(int position){ //########### } //写文件流 @Override public void write(char data){ //########### }}class MemoryStream extends Stream { //读文件流 @Override public char read(int number){ //@@@@@@@@@@@ } //定位文件流 @Override public void seek(int position){ //@@@@@@@@@@@ } //写文件流 @Override public void write(char data){ //@@@@@@@@@@@ }}/** * 一个基类,用于提取CryptoStream和BufferedStream共同的成员变量s * 因为这个类没有继承父类所有属性,所以是抽象类 * 根据重构的原则,继承自同一父类的几个子类含有相同的字段或变量时,应该把它往上提, * 而直接放在Stream类里面的话,会影响FileStream、MemoryStream等类的使用,所以我们就要一个基类实现重构 *///继承:接口协议abstract DecroratorStream extends Stream{ //组合:复用实现 protected Stream s;// s=new FileStream(); s=new NetworkStream(); s=new MemoryStream(); protected DecroratorStream(Stream s){ this.s=s; }}class CryptoStream extends DecroratorStream { public CryptoStream(Stream s) { //改为继承父类的方法 super(s); } @Override public char read(int number) { //额外的加密操作... //读文件流 s.read(number); } @Override public void seek(int position) { //额外的加密操作... //定位文件流 s.seek(position); //额外的加密操作... } //写内存流 @Override public void write(char data) { //额外的加密操作... //写文件流 s.write(data); //额外的加密操作... }}class BufferedStream extends DecroratorStream { Stream s; public BufferedStream(Stream s) { super(s); } //....}class Client { public static void main(String args[]) { //运行时装配 FileStream fs=new FileStream(); Stream s1=new CryptoStream( new FileStream()); Stream s2 = new BufferedStream(new FileStream()); Stream s3 = new CryptoStream(new BufferedStream(new FileStream())); }}现在逻辑结构如下图,可以看到,我们的代码结构简洁了很多!
◆ 模式定义:
动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活(消除重复代码&减少子类个数)。
◆ 要点总结:
● 通过采用组合而非继承的手法,Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”;
● Decorator类在接口上表现为 is-a Component的继承关系,即Decorator类继承了Component类所有的接口。但在实现上又表现为 has-a Component的组合关系,即Decorator类又使用了另一个Component类。这就是Decorator模式的典型特征;(见下图)
● Decorator模式的目的并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主题类在多个方向上的扩展功能” —— 是为“装饰”的含义;
0 0
- 面向对象的设计模式(二)——Decorator模式
- Java面向对象设计模式(七)——装饰模式(Decorator)
- 面向对象的设计模式(二),Builder模式
- 设计模式与面向对象学习--decorator模式
- 设计模式——面向对象设计的原则(二)
- 设计模式(Design Patterns)-可复用面向对象软件的基础 07:装饰模式(Decorator)
- C#面向对象设计模式纵横谈 学习笔记10 Decorator 装饰(结构型模式)
- 面向对象设计模式之Decorator装饰模式(结构型)
- 设计模式12—Decorator设计模式
- Java面向对象设计模式(二十)——状态模式(State)
- Java面向对象设计模式(二十一)——访问者模式(Visitor)
- Java面向对象设计模式(二十二)——中介者模式(Mediator)
- Java面向对象设计模式(二十三)——解释器模式(Interpreter)
- 【面向对象】——设计模式之行为型模式(二)
- 可复用面向对象软件基础——设计模式(二)之工厂方法模式
- Java面向对象设计模式(二)——抽象工厂模式
- 【面向对象设计模式】 适配器模式 (二)
- JavaScript面向对象设计二——构造函数模式
- JDBC-Java数据库连接
- hive启动报错 java.net.URISyntaxException: Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%7B
- 分享C++11代码片段-tuple和chrono
- Unable to convert MySQL datetime value to System.DateTime 解决方案
- 解决ecplise提示需要移除@Override的问题
- 面向对象的设计模式(二)——Decorator模式
- 解决Android Studio 导入外部项目时报错:Could not find method android() for arguments
- UVALive 5695 -The Last Puzzle -区间dp
- delegate() 方法
- MAC Apache 启动 停止 重启命令
- web学习(2)--别踩白块儿(js版)(web入门)
- 王播求钟情中国美女护士,身体反应把他出卖了
- 用原生js来将prompt()方法得到的字符串,转换为数字,并进行运算呢?
- HDU 1861