11.装饰模式(Decorator Pattern)

1.定义

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更灵活。

 

2.装饰模式的使用场景

  • 需要扩展一个类的功能,或给一个类增加附加功能
  • 需要动态地给一个对象增加功能,这些功能可以动态的撤销
  • 需要为一批的兄弟类进行改装或者加装功能,当然是首选装饰模式

3.例子

我买了一辆车,这辆车会跑。
那么用代码抽象上面这句话就成了这样:

 

package _11DecoratorPattern;

public interface ICar {

	public void run();
}
 
package _11DecoratorPattern;

public class MyCar implements ICar {

	@Override
	public void run() {
		System.out.println("我的车跑到了七十码");
	}
}

在我开车的时候,突然觉得要是我的车有放音乐的功能就好了。
那么我们去修改MyCar实现类吗?基于开闭原则,我想这不是一个好方案。
这让我想起来了或许参考以前的代理模式能实现这个功能:

 

package _11DecoratorPattern;

public class MyMusicCar implements ICar {
	
	private ICar car;

	public MyMusicCar(ICar car)
	{
		this.car = car;
	}
	
	@Override
	public void run() 
	{
		System.out.println("最炫民族风正在响起……");
		car.run();
	}
}

好了,上面这个代码就是装饰模式。
是不是很简单?可能你要有疑问了:这不是代理模式吗?
首先要说的是,装饰模式就是代理模式的一个特殊应用,两者的共同点是都具有相同的接口,不同点是代理模式注重于对代理过程的控制(比如上面的代码如果是代理模式实现会在run里面判断油量是否充足,如果不充足,它代理的车子将不能调用run方法),而装饰模式则是对类的功能进行加强或减弱,它着重于类的功能变化。

 

4.装饰模式的四个组件

  • Component抽象构件:一个接口或者抽象类,就是定义我们最核心的对象,也就是原始的对象。
  • ConcreteComponent具体构件:是最核心、最原始、最基本的接口或抽象类的实现,你要修饰的就是它。
  • Decorator抽象装饰角色:一般是一个抽象类,在它的属性里必然有一个private变量指向Component抽象构件
  • 具体装饰角色

5.装饰模式的通用代码

package _11DecoratorPattern;

// 抽象构件
public abstract class Component {
	
	// 抽象的方法
	public abstract void operation();
}
 
package _11DecoratorPattern;

// 具体构件
public class ConcreteComponent extends Component {

	// 具体实现
	@Override
	public void operation() {
		System.out.println("do some thing");
	}

}
 
package _11DecoratorPattern;


// 抽象装饰类,如果只需要一个装饰,那么直接在operation方法中实现,不需要别的装饰类,否则,继续看下面的装饰类
public abstract class Decorator extends Component {

	private Component component;
	
	// 通过构造函数传递被修饰者
	public Decorator(Component component)
	{
		this.component = component;
	}
	
	// 委托给被修饰者执行
	@Override
	public void operation() {
		this.component.operation();
	}
}
 
package _11DecoratorPattern;

public class ConcreteDecorator1 extends Decorator {

	public ConcreteDecorator1(Component component) {
		super(component);
	}

	// 定义自己的修饰方法
	private void method2() {
		System.out.println("method2 修饰");
	}
	// 重写父类的修饰方法
	@Override
	public void operation() {
		super.operation();
		this.method2();
	}

}
 
package _11DecoratorPattern;

public class ConcreteDecorator2 extends Decorator {

	public ConcreteDecorator2(Component component) {
		super(component);
	}

	// 定义自己的修饰方法
	private void method1() {
		System.out.println("method1 修饰");
	}
	// 重写父类的修饰方法
	@Override
	public void operation() {
		this.method1();
		super.operation();
	}

}
 
package _11DecoratorPattern;

// 场景类
public class Client {

	public static void main(String[] args) {
		Component component = new ConcreteComponent();
		// 第一次被修饰
		component = new ConcreteDecorator1(component);
		// 第二次被修饰
		component = new ConcreteDecorator2(component);
		component.operation();
	}
}
 
结果输出:
method1 修饰
do some thing
method2 修饰

6.装饰模式的优点

  • 装饰类和被装饰类可以独立发展,而不会相互耦合。换句话说,Component类无需知道Decorator类,Decorator类是从外部扩展Component类的功能,而Decorator也不不用知道具体的构件。
  • 装饰模式是继承关系的一个替代方案。我们看装饰类Decorator,不关装饰多少层,返回的对象还是Component,实现的还是is-a的关系。
  • 装饰模式可以动态地扩展一个实现类的功能。

7.装饰模式的缺点

多层的装饰是比较复杂的。为什么会负责呢?你想想看,就像剥洋葱一样,你剥到了最后才发现是最里层的装饰出现了问题,想象一下工作了吧。因此,尽量减少装饰类的数量,以便降低系统的复杂度。

猜你喜欢

转载自wangwengcn.iteye.com/blog/1720413