前言
我们通常在编码的时候为了扩展一个类的功能往往用的是继承来实现,但是继承的缺点主要是单继承的局限性和可能产生类爆炸的后果。
装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。装饰模式属于结构型模式,它是作为现有的类的一个包装。
结构模式图
解析:
- Component:定义一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent:定义了一个具体的对象,也可以给这个对象添加一些职责。
- Decorator:装饰抽象类,继承了 Component,从外类来扩展Component的功能,但对于Component来说,是无需知道Decorator的存在的。
- ConcreteDecoratorA/B:具体的装饰对象,起到给Component添加职责的功能。
案例实现
想想一下这个情景:清晨上班的你在路上遇到一家面馆,你便进去点了一碗面吃,然后你又发现菜单栏上有许多的配料:牛肉、荷包蛋、鸡腿,这时你看到旁边的一个老板把这三个全部点了一遍加到他的面里,于是你也不甘示弱,但作为程序员的你只加了一个荷包蛋进去。
现在我们用装饰模式来完成上面这个需求:往面条里面加配料,上代码:
我们先定义一个对象接口:INoodles
package com.design_pattern.decorator;
/**
* Created on 2020/3/19
* Package com.design_pattern.decorator
*
* @author dsy
*/
public interface INoodles {
public void cook();
}
然后写一个具体的实现类:Noodles
package com.design_pattern.decorator;
/**
* Created on 2020/3/19
* Package com.design_pattern.decorator
*
* @author dsy
*/
public class Noodles implements INoodles {
@Override
public void cook() {
System.out.println("的面条");
}
}
定义一个抽象装饰类:NoodlesDecorator
package com.design_pattern.decorator;
/**
* Created on 2020/3/19
* Package com.design_pattern.decorator
*
* @author dsy
*/
public abstract class NoodlesDecorator implements INoodles {
private INoodles noodles; //添加一个INoodles 的引用
public NoodlesDecorator(INoodles noodles){ //通过构造器来设置INoodles
this.noodles = noodles;
}
@Override
public void cook() {
if (noodles!=null){
noodles.cook();
}
}
}
具体装饰类:EggDecorator
package com.design_pattern.decorator;
/**
* Created on 2020/3/19
* Package com.design_pattern.decorator
*
* @author dsy
*/
public class EggDecorator extends NoodlesDecorator {
public EggDecorator(INoodles noodles) {
super(noodles);
}
/**
* 重写父类的cook方法,并添加自己的实现,调用父类的cook方法,此cook方法是通过本类的构造器
* EggDecorator(INoodles noodles)传入的noodles的cook操作
*/
@Override
public void cook() {
System.out.println("加了一个荷包蛋");
super.cook();
}
}
具体装饰类:BeefDecorator
package com.design_pattern.decorator;
/**
* Created on 2020/3/19
* Package com.design_pattern.decorator
*
* @author dsy
*/
public class BeefDecorator extends NoodlesDecorator {
public BeefDecorator(INoodles noodles) {
super(noodles);
}
@Override
public void cook() {
System.out.println("加了一斤牛肉");
super.cook();
}
}
具体装饰类:ChickenLegDecorator
package com.design_pattern.decorator;
/**
* Created on 2020/3/19
* Package com.design_pattern.decorator
*
* @author dsy
*/
public class ChickenLegDecorator extends NoodlesDecorator {
public ChickenLegDecorator(INoodles noodles) {
super(noodles);
}
@Override
public void cook() {
System.out.println("加了一个鸡腿");
super.cook();
}
}
package com.design_pattern.decorator;
/**
* Created on 2020/3/19
* Package com.design_pattern.decorator
*
* @author dsy
*/
public class Client {
public static void main(String[] args) {
//一位老板来了说我全要
INoodles noodles = new Noodles();
INoodles noodlesWithEgg = new EggDecorator(noodles);
INoodles noodlesWithEggAndChickenLeg = new ChickenLegDecorator(noodlesWithEgg);
INoodles noodlesWithEggAndChickenLegAndBeef = new BeefDecorator(noodlesWithEggAndChickenLeg);
noodlesWithEggAndChickenLegAndBeef.cook();
System.out.println("************分割线**************");
//咱是程序员,咱加一个蛋就行了
INoodles noodles1 = new Noodles();
INoodles noodles1WithEgg = new EggDecorator(noodles1);
noodles1WithEgg.cook();
}
}
打印输出:
加了一斤牛肉
加了一个鸡腿
加了一个荷包蛋
的面条
************分割线**************
加了一个荷包蛋
的面条
总结
优缺点分析:
优点:
- 装饰类和被装饰类可以独立发展,不会相互耦合。
- 装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:
- 多层装饰比较复杂。
使用场合:
- 如果你希望在无需修改代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为, 可以使用装饰模式。
- 如果用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用该模式。