我们都知道,可以使用两种方式给一个类或者对象添加行为。
一是使用继承。继承是给一个类添加行为的比较有效的途径。通过使用继承,可以使得子类在拥有自身方法的同时,还可以拥有父类的方法。但是使用继承是静态的,在编译的时候就已经决定了子类的行为,我们不便于控制增加行为的方式和时机。
二是使用关联。组合即将一个对象嵌入到另一个对象中,由另一个对象来决定是否引用该对象来扩展自己的行为。这是一种动态的方式,我们可以在应用程序中动态的控制。
与继承相比,关联关系的优势就在于不会破坏类的封装性,且具有较好的松耦合性,可以使系统更加容易维护。但是它的缺点就在于要创建比继承更多的对象。
装饰者模式:
通过组合动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比“继承”更为灵活。
涉及角色:
抽象构件角色:定义一个抽象接口,来规范准备附加功能的类。具体构件角色:将要被附加功能的类,实现抽象构件角色接口。抽象装饰者角色:持有对具体构件角色的引用并定义与抽象构件角色一致的接口。具体装饰角色:实现抽象装饰者角色,负责为具体构件添加额外功能。
模式要点
(1)要求装饰对象和被装饰对象实现同一个接口
(2)装饰对象持有被装饰对象的实例
模式实现
抽象构件角色:
public interface Component{ //默认方法A void functionA();}
具体构件角色:
public class ConcreateComponent implements Component{ public void functionA() { System.out.println("Function A"); } }
抽象装饰者角色:
public class Decorator implements Component{ //抽象构件角色的引用 private Component component; public Decorator(Component component) { this.component = component; } public void functionA() { component.functionA(); } }
具体装饰者角色1:
public class ConcreateDecoratorOne extends Decorator{ public ConcreateDecoratorOne(Component component) { super(component); } @Override public void functionA() { super.functionA(); this.functionB(); } //根据自己的需要扩展 private void functionB() { System.out.println("function B"); }}
具体装饰者角色2:
public class ConcreateDecoratorTwo extends Decorator{ public ConcreateDecoratorTwo(Component component) { super(component); } @Override public void functionA() { super.functionA(); this.functionC(); } private void functionC() { System.out.println("fucntion C"); }}
测试类:
public class Client{ public static void main(String[] args) { // 一层套一层,进行方法组合 Component component = new ConcreateDecoratorTwo(new ConcreateDecoratorOne( new ConcreateComponent())); component.functionA(); } }
模式总结
优点:
1、装饰者模式可以提供比继承更多的灵活性
2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
缺点:
1、会产生很多的小对象,增加了系统的复杂性
2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。