一、装饰器模式定义
1、动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活
Component抽象构件
Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象,定义一个对象接口可以给这些对象动态地添加职责
ConcreteComponent 具体构件
ConcreteComponent是最核心、最原始、最基本的接口或抽象类的实现,需要装饰的就是它Decorator装饰角色
一般是一个抽象类,在它的属性里必然有一个private变量指向Component抽象构件。
具体装饰角色
ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,要把最核心的、最原始的、最基本的东西装饰成其他东西
/**
* 抽象构件
*/
public abstract class Componet {
/**
* 抽象方法
*/
public abstract void operate();
}
/**
* 具体构件
*/
public class ConcreteComponet extends Componet {
@Override
public void operate() {
//具体的实现
System.out.println("do something");
}
}
/**
* 装饰类
*/
public class Decorator extends Componet {
private Componet componet = null;
/**
* 通过构造函数传递被修饰者
*
* @param componet
*/
public Decorator(Componet componet) {
this.componet = componet;
}
/**
* 委托给被修者执行
*/
@Override
public void operate() {
this.componet.operate();
}
}
/**
* 具体的装饰类
*/
public class ConcreteDecoratorA extends Decorator {
/**
* 通过构造函数传递被修饰者
*
* @param componet
*/
public ConcreteDecoratorA(Componet componet) {
super(componet);
}
/**
* 定义自己的修饰方法
*/
private void method1() {
System.out.println("修饰DecoratorA");
}
@Override
public void operate() {
this.method1();
super.operate();
}
}
/**
* 具体的装饰类
*/
public class ConcreteDecoratorB extends Decorator {
/**
* 通过构造函数传递被修饰者
*
* @param componet
*/
public ConcreteDecoratorB(Componet componet) {
super(componet);
}
/**
* 定义自己的修饰方法
*/
private void method2() {
System.out.println("修饰方法DecoratorB");
}
@Override
public void operate() {
//重写父类的operate方法
this.method2();
super.operate();
}
}
public class Client {
public static void main(String[] args) {
Componet componet = new ConcreteComponet();
//第一次修饰
componet = new ConcreteDecoratorA(componet);
//第二次修饰
componet= new ConcreteDecoratorB(componet);
//修饰后运行
componet.operate();
}
}
煎饼有基础套餐,另外可以加鸡蛋,加菜等,可以用装饰模式表示
/**
* 煎饼,抽象构建
*/
public abstract class Pancake {
/**
* 套餐
* @return
*/
public abstract String getMsg();
/**
* 价格
* @return
*/
public abstract Integer getPrice();
}
/**
* 具体套餐
*/
public class BasicsPancake extends Pancake {
@Override
public String getMsg() {
return "一张煎饼";
}
@Override
public Integer getPrice() {
return 3;
}
}
片
/**
* 加鸡蛋
*/
public class EggDecorator extends PancakeDecorator{
/**
* 通过构造函数传递被修饰者
*
* @param pancake
*/
public EggDecorator(Pancake pancake) {
super(pancake);
}
@Override
public String getMsg() {
return super.getMsg()+"加1个鸡蛋";
}
@Override
public Integer getPrice() {
return super.getPrice()+2;
}
}
/**
* 加蔬菜
*/
public class GreensDecorator extends PancakeDecorator{
/**
* 通过构造函数传递被修饰者
*
* @param pancake
*/
public GreensDecorator(Pancake pancake) {
super(pancake);
}
@Override
public String getMsg() {
return super.getMsg()+"加1份生菜";
}
@Override
public Integer getPrice() {
return super.getPrice()+1;
}
}
public class Client {
public static void main(String[] args) {
Pancake basicsPancake = new BasicsPancake();
basicsPancake = new EggDecorator(basicsPancake);
basicsPancake = new GreensDecorator(basicsPancake);
//一张煎饼加1个鸡蛋加1份生菜:价钱:6
System.out.println(basicsPancake.getMsg() +":价钱:"+ basicsPancake.getPrice());
}
}
二、装饰模式的优点
1、装饰类和被装饰类可以独立发展,而不会相互耦合。换句话说,Component类无须知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的构件
2、装饰模式是继承关系的一个替代方案。我们看装饰类Decorator,不管装饰多少层,返回的对象还是Component,实现的还是is-a的关系
3、装饰模式可以动态地扩展一个实现类的功能
三、装饰模式的缺点
多层的装饰是比较复杂的,就像剥洋葱一样,你剥到了最后才发现是最里层的装饰出现了问题
四、例子
●抽象构件(Component)角色:由InputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。
●具体构件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口。
●抽象装饰(Decorator)角色:由FilterInputStream扮演。它实现了InputStream所规定的接口。
●具体装饰(ConcreteDecorator)角色:由几个类扮演,分别是BufferedInputStream、DataInputStream以及两个不常用到的类LineNumberInputStream、PushbackInputStream。
四、使用场景
1、需要扩展一个类的功能,或给一个类增加附加功能。
2、需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
3、 需要为一批的兄弟类进行改装或加装功能,首选装饰模式。
五、与代理模式的区别
代理模式专注于对被代理对象的访问;
装饰器模式专注于对被装饰对象附加额外功能。