1.简介
概念:装饰模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
逻辑点
抽象组件(Component):给对象动态的添加职责。
ConcreteComponent:组件具体实现类。
抽象装饰者(Decorator):继承Component,从外类来拓展Component类的功能,但对于Component来说无需知道Decorator的存在。
ConcreteDecorator:装饰者具体实现类。
2.装饰模式的实现
需求:一位程序员同学会java语言,还想学C语言,OC语言。这样又有俩位老师给他分别讲解C,OC,这样这个同学就会了java,C,OC语言。
抽象组件(Component)
作为一名学生肯定具备学习能力,我们先定义一个学习能力的抽象类,包具备学习的抽象方法:
public abstract class Study{
public abstract void startStudy();
}
组件具体实现类(ConcreteComponent)
被装饰的具体对象,在这里就是要学习的具体的语言:
public class ChengXuyuan extends Study{
@Override
public void startStudy() {
//程序员初始的语言java
System.out.println("程序员使用java语言");
}
}
抽象装饰者(Decorator)
抽象装饰者保持了一个对抽象组件的引用,方便调用被装饰对象中的方法,老师拥有对学习的引用:
public abstract class Teacher extends Learn{
private Learn mLearn;
public Teacher(Learn learn){
this.mLearn = learn;
}
@Override
public void startLearn() {
mStudy.startLearn();
}
}
装饰者具体实现类(ConcreteDecorator)
用两个装饰者具体实现类,分别是Cteacher和OCteacher,他们负责来传授杨过新的武功:
public class Cteacher extends Teacher {
public Cteacher(Learn learn) {
super(learn);
}
public void teachC(){
System.out.println("Cteacher教授C语言");
System.out.println("程序员学会使用C语言");
}
@Override
public void startStudy() {
super.startLearn();
teachC();
}
}
public class OCteacher extends Teacher{
public OCteacher(Learn learn) {
super(learn);
}
public void teachOC(){
System.out.println("OCteacher教授OC语言");
System.out.println("程序员学会使用OC语言");
}
@Override
public void startLearn() {
super.startLearn();
teachOC();
}
}
客户端调用
程序员经过C teacher和OC teacher的教导,除了初始会的java语言,又学会了C语言和OC语言:
public class ClientUse {
public static void main(String[] args){
//创建程序员
ChengXuyuan mChengXuyuan = new ChengXuyuan();
//学习C语言
Cteacher mCteacher = new Cteacher(mChengXuyuan);
mCteacher.startLearn();
//学习OC语言
OCteacher mOCteacher = new OCteacher(mCteacher);
mOCteacher.startLearn();
}
}
3.优缺点
优点
a.通过组合而非继承的方式,动态的来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
b.有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
c.具体组件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体组件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
缺点
a.多层装饰比较复杂
b.因为所有对象都是继承于Component,所以如果Component内部结构发生改变,则不可避免地影响所有子类(装饰者和被装饰者),如果基类改变,势必影响对象的内部。
c.比继承更加灵活机动的特性,装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐,所以只在必要的时候使用装饰者模式。
使用场景
a.扩展一个类的功能,在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
b.当需要我们动态地给一个对象增加功能,而且这些功能可以动态的撤销。
c.当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。