一、场景
增加车的功能
二、实质
动态的为一个对象增加新的功能,是一种用于代替继承的技术,无须通过继承增加新的子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
三、实现细节
Component抽象构件角色
真实对象与装饰对象有相同的接口,这样客户端对象就能够以与真实对象相同的方式同装饰对象交互。
ConcreteComponent具体构件角色(真实对象)
Decorator装饰角色
持有一个抽象构件的引用,装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象,这样就能在真实对象调用前后增加新的功能。
ConcreteDecorator具体装饰角色
负责给构件对象增加新的责任。
四、示例
实例1
package IOOthers;
public class Voice {
private int voice = 10;
public Voice() {
}
public Voice(int voice) {
super();
this.voice = voice;
}
public int getVoice() {
return voice;
}
public void setVoice(int voice) {
this.voice = voice;
}
public void say()
{
System.out.println(voice);
}
}
class Amplifier {
private Voice voice;
public Amplifier() {
}
public Amplifier(Voice voice) {
super();
this.voice = voice;
}
public void say()
{
System.out.println(voice.getVoice()*1000);
}
}
package IOOthers;
/**
* 扩音器
* 类与类之间的关系
* 1、依赖:形参|局部变量
* 2、关联:属性
* 聚合:属性 整体与部分 不一致的生命周期 人与手
* 组合:属性 整体与部分 一致的生命周期 人与大脑
* 3、继承:父子类关系
* 4、实现:接口与实现类关系
*/
public class Demo09 {
public static void main(String[] args) {
Voice v = new Voice(20);
v.say();
Amplifier am = new Amplifier(v);
am.say();
}
}
运行结果:
20
20000
实例2
package com.lgd.decorator;
/**
* 抽象组件
* @author liguodong
*
*/
public interface ICar {
void move();
}
//具体构建对象(真实对象)
class Car implements ICar{
@Override
public void move() {
// TODO Auto-generated method stub
System.out.println("陆地上跑");
}
}
//装饰器角色
class SuperCar implements ICar{
private ICar car;
public SuperCar(ICar car) {
super();
this.car = car;
}
@Override
public void move() {
// TODO Auto-generated method stub
car.move();
}
}
//具体装饰角色
class FlyCar extends SuperCar{
public FlyCar(ICar car) {
super(car);
// TODO Auto-generated constructor stub
}
public void fly(){
System.out.println("天上飞");
}
@Override
public void move() {
// TODO Auto-generated method stub
super.move();
fly();
}
}
//具体装饰角色
class WaterCar extends SuperCar{
public WaterCar(ICar car) {
super(car);
// TODO Auto-generated constructor stub
}
public void Water(){
System.out.println("水上游");
}
@Override
public void move() {
// TODO Auto-generated method stub
super.move();
Water();
}
}
//具体装饰角色
class AICar extends SuperCar{
public AICar(ICar car) {
super(car);
// TODO Auto-generated constructor stub
}
public void AI(){
System.out.println("自动跑");
}
@Override
public void move() {
// TODO Auto-generated method stub
super.move();
AI();
}
}
package com.lgd.decorator;
import java.awt.CardLayout;
public class Client {
public static void main(String[] args) {
Car car = new Car();
car.move();
System.out.println("增加新的功能,飞行-----");
FlyCar flyCar = new FlyCar(car);
flyCar.move();
System.out.println("增加新的功能,水里游-----");
WaterCar waterCar = new WaterCar(car);
waterCar.move();
System.out.println("增加新的功能,水里游天上飞-----");
WaterCar waterflyCar = new WaterCar(new FlyCar(new Car()));
waterflyCar.move();
}
}
运行结果:
陆地上跑
增加新的功能,飞行-----
陆地上跑
天上飞
增加新的功能,水里游-----
陆地上跑
水上游
增加新的功能,水里游天上飞-----
陆地上跑
天上飞
水上游
五、应用场景
IO中的输入流和输出流的设计
Swing包中图形界面构建功能
Servlet API中提供了一个request对象的Decoratot设计模式的默认实现类HttpServletRequestWrapper,增强了request的功能。
Struct2中,request,response,session对象的处理
六、总结
装饰模式(Decorator)也叫包装器模式(Wrapper)
装饰模式降低了系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类可以独立变化,一边增加新的具体构建类和具体装饰类。
优点:
扩展对象功能,比继承灵活,不会导致类个数的急剧增加。
可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更强大的对象。
具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类。
缺点:
产生很多小的对象,大量小对象占据内存,一定程度上影响性能。
装饰模式易于出错,调试排查比较麻烦。
七、装饰模式和桥接模式的区别
都是为了解决多子类对象问题,但他们的诱因不一样。
桥接模式是对象自身现有机制沿着多个维度变化,是有部分不稳定。
装饰模式是为了增加新的功能。