当我们需要动态地给一个类添加职责或者功能的时候我们可以考虑使用装饰者模式。
一、装饰者模式的使用场景
(1)在不影响其他对象的情况下,以动态地,透明地方式给对象添加功能。
(2)处理一些可以撤销的职责。
(3)当不能采用生成子类的方式进行扩展的时候,就可以使用装饰者模式。有两种情况可以使用装者模式,一种是:可能有大量的扩展,如果要扩展这些功能,可能会造成太多的子类。另一种是,不允许有子类的情况。
二、装饰者模式所涉及的对象
(1)抽象被装饰者:定义装饰者和被装饰者的公共方法。这里需要注意的有两点,第一点是:这个抽象被装饰者建议使用接口。第二点是无论装饰者还是被装饰者都需要继承这个抽象被装饰者。
(2)具体被装饰者:集成自抽象被装饰者,并且实现自己需要实现的方法。
(3)抽象装饰者:抽象类,并且持有被装饰者,并且在自己的方法中需要调用被装饰者的相应方法。
(4)具体装饰者:这里需要注意的是这个对象是给自己持有的具体被装饰者增加需要的装饰行为。简单点说就是在自己的方法中不仅仅要调用父类的方法,因为父类的方法最终会调用相应的被装饰者的方法。同时还需要实现自己对应的装饰行为。
三、实现装饰者模式需要注意以下几点:
(1)装饰者和被装饰者其实都继承自相同的类,也就是抽象被装饰者。
(2)装饰者持有被装饰者。
(3)使用装饰者的对象,最终都会调用被装饰者对应的方法。
(4)不需要使用继承。
四、具体实例
(1)抽象被装饰者
package com.liutao.design.model.decorator;
/**
* show how to use the model of decorator
*
* @author LIUTAO
* @version 2017/10/28
* @see
*/
public interface Bread {
void myType();
}
可以看出上面的抽象被装饰类定义了一个面包接口,并且这个接口有一个方法。
(2)具体被装饰类
package com.liutao.design.model.decorator;
/**
* show how to use the model of decorator
*
* @author LIUTAO
* @version 2017/10/28
* @see
*/
public class SimpleBread implements Bread {
@Override
public void myType() {
System.out.println("I'm bread。");
}
}
实现了自己相应的方法。
(3)抽象装饰者
package com.liutao.design.model.decorator;
/**
* show how to use the model of decorator
*
* @author LIUTAO
* @version 2017/10/28
* @see
*/
public abstract class BreadDecorator implements Bread {
private Bread bread;
public BreadDecorator(Bread bread) {
this.bread = bread;
}
public void setBread(Bread bread) {
this.bread = bread;
}
public void myType(){
bread.myType();
}
}
可以看出抽象装饰者继承自被装饰者,并且持有具体被装饰者,在自己的方法中调用的其实是相应的被装饰的相应方法。
(4)具体装饰者
package com.liutao.design.model.decorator;
/**
* show how to use the model of decorator
*
* @author LIUTAO
* @version 2017/10/28
* @see
*/
public class ButterDecorator extends BreadDecorator {
public ButterDecorator(Bread bread) {
super(bread);
}
public void myType(){
super.myType();
butterType();
}
public void butterType(){
System.out.println("add butter.");
}
}
package com.liutao.design.model.decorator;
/**
* show how to use the model of decorator
*
* @author LIUTAO
* @version 2017/10/28
* @see
*/
public class MilkDecorator extends BreadDecorator {
public MilkDecorator(Bread bread) {
super(bread);
}
public void myType(){
super.myType();
milkType();
}
public void milkType(){
System.out.println("add milk.");
}
}
(5)测试类
package com.liutao.design.model.decorator;
/**
* show how to use the model of decorator
*
* @author LIUTAO
* @version 2017/10/28
* @see
*/
public class TestDemo {
public static void main(String[] args) {
SimpleBread simpleBread = new SimpleBread();
ButterDecorator butterDecorator = new ButterDecorator(simpleBread);
MilkDecorator milkDecorator = new MilkDecorator(butterDecorator);
milkDecorator.myType();
}
}
在这里我们可以看出一个面包即使他是黄牛面包还是普通面包其实都是面包,这也就是我们需要装饰者持有被装饰者的原因。
(6)输出如下
I'm bread。
add butter.
add milk.
总结:在这个地方,我们就要问这个地方如果我们使用继承也可以实现,那么为什么我们还要使用装饰者模式呢?那么我就要问,如果我需要在加入黄油和牛奶的中间加入鸡蛋
,怎么办呢?是不是就需要改变类的集成结构了?这样一来就会影响到其他使用这个类的地方,但是如果我们使用装饰着模式,就仅仅需要再增加一个装饰类就可以了。