Posted on 2006-12-24 14:36
acooly 阅读(970)
评论(0) 编辑 收藏 所属分类:
Java开发 、
设计模式
装饰(Decorator)模式又名包装(Wrapper)模式。Decorator以对客户端透明的方式扩展对象的功能,是继承的一种代替方案。
1.什么时候使用- 需要动态的扩展一个类,这些扩展也可以动态的撤销,并保持原有类的静态定义的情况。
- 需要增加由一些基本功能排列组合贰产生的非常强大的功能,并使继承关系变得不实现,典型的Wrapper应用。
模拟类图:
在装饰模式中的各个角色有:
- 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
- 具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
- 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- 具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。
2.示例代码
在一个实际的项目中,给部分用户增加了一个网络硬盘的服务。要对原来的用户注册方法进行扩展完成注册的时候给用户开通和绑定网络硬盘的功能,又要保持原来注册的功能。我考虑使用decorator模式添加一个装饰的用户管理类扩展原有的管理类来实现。
/**
* 用户管理抽象接口(Component)
*/
public interface UserManager{
public void register(User user);
}
/**
* 原有用户管理具体类(Concrete Component)
*/
public class DefaultUserManager implements UserManager{
public void register(User user){
//常规注册实现
}
}
/**
* 用户管理具体装饰类NetDiskManager(只有一个装饰对象的情况,装饰类和具体装饰类合并)
*/
public class NetdiskUserManager implements UserManager{
private UserManager userManager;
public NetdiskUserManager(UserManager userManager){
this.userManager = userManager;
}
public void register(User user){
bandingNetdisk(user);
userManager.register(user);
}
private void bandingNetdisk(User user){
//实现绑定网络硬盘服务。
}
}
3.在JDK-io包中的应用在jdk-io包中标准输入输出流等相关类库都大量使用了Decorator模式。如OutputStream与其相关子类的实现。
请参考:
http://redlly.blog.hexun.com/2545654_d.html4.使用装饰模式的优点和缺点使用装饰模式主要有以下的优点:
- 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
- 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
- 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错。
使用装饰模式主要有以下的缺点:
由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。
5.使用装饰模式的讨论大多数情况下,装饰模式的实现都比上面定义中给出的示意性实现要简单。对模式进行简化时需要注意以下的情况:
(1)一个装饰类的接口必须与被装饰类的接口相容。
(2)尽量保持Component作为一个"轻"类,不要把太多的逻辑和状态放在Component类里。
(3)如果只有一个ConcreteComponent类而没有抽象的Component类(接口),那么Decorator类经常可以是ConcreteComponent的一个子类。
(4)如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。
透明的装饰模式
所谓透明是指对客户端程序员来说是针对接口编程,而不是具体的继承或实现类。引用彦博士的《java与模式》的说法是:“必须永远把孙悟空的所有变化都当成孙悟空来对待,而如果把老孙变成的雀儿当成雀儿,而不是老孙,那就被老孙骗了,而这是不应当发生的。”
下面的做法是对的:
Component c = new ConcreteComponent();
Component c1 = new ConcreteDecorator1(c);
Component c2 = new ConcreteDecorator(c1);
而下面的做法是不对的:
ConcreteComponent c = new ConcreteDecorator();
半透明的装饰模式
然而,纯粹的装饰模式很难找到。装饰模式的用意是在不改变接口的前提下,增强所考虑的类的性能。在增强性能的时候,往往需要建立新的公开的方法。即
便是在孙大圣的系统里,也需要新的方法。比如齐天大圣类并没有飞行的能力,而雀儿有。这就意味着雀儿应当有一个新的fly()方法。
这就导致了大多数的装饰模式的实现都是"半透明"(semi-transparent)的,而不是完全"透明"的。换言之,允许装饰模式改变接口,
增加新的方法。即声明ConcreteDecorator类型的变量,从而可以调用ConcreteDecorator类中才有的方法:
齐天大圣 c = new 大圣本尊();
雀儿 bird = new 雀儿(c);
bird.fly();
齐天大圣接口根本没有fly()这个方法,而雀儿接口里有这个方法。
参考:
《java与模式》
google搜索:"java decorator"