装饰者模式定义
装饰器模式,英文名为Decorator Pattern,它的核心思想:就是通过一些“装饰品”对原有的基础类进行包装,从而增强或者是完成某些特定的功能。
装饰器模式,可以动态地将新功能附加到对象上,并且在对象的扩展方面,使用该模式要比单纯的通过继承更加有弹性。
装饰者模式应用场景
1.扩展一个类的功能:在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2.当不能采用继承的方式对系统进行扩充,或者采用继承不利于系统扩展和维护时,建议使用装饰者模式。
装饰者模式角色
装饰者模式角色,主要包含4大角色,如下图所示:
1.抽象构件
Component(抽象构件):定义了全部组件类,它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法
2.具体构件
ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
3.装饰角色
装饰器抽象类Decorator:实现Component接口的抽象类,在其中封装了一个Component 对象, 也就是被装饰的对象。
4.具体装饰器
具体装饰器ConcreteDecorator:它是抽象装饰类的子类,负责向构件添加新的职责,每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
装饰者模式示例
看一个具体的例子(火锅店吃火锅拌蘸料),蘸料有很多:而每个人的口味又不一样,所以组合就非常多,这种情况下如果使用装饰着模式。
示例如下,装饰者模式分为如下四步:
第一步:组件(Component)
首先我们有一个行为拌蘸料(Component),如下所示:
/** * 装饰着模式 - * 组件(Component):组件接口定义了全部组件类和装饰器实现的行为 */ public interface AllocatSeasoning { void allo(); }
接下来,按照上面装饰者的模型进行分析,我们需要2个类来实现上面的行为拌蘸料(Component)。
第二步:组件实现类(ConcreteComponent)
第一个类ConcreteComponent:可以理解为装拌料的碗,后面的加蘸料都放到这个碗里面,如下所示:
/** * 组件实现类(ConcreteComponent): * 实现Component接口,组件实现类就是被装饰器装饰的原始对象, * 新功能或者附加功能都是通过装饰器添加到该类的对象上的; * * 可以把这个理解为装拌料的碗 */ public class AllocDo implements AllocatSeasoning{ @Override public void allo() { System.out.println("----- 您好,这边是调料自选区,可以按照您的口味选择自己喜欢的口味 -----"); } }
第三步:装饰器抽象类
/** * 装饰器抽象类(Decorator): * 实现Component接口的抽象类,在其中封装了一个Component 对象, * 也就是被装饰的对象; * * 这个对象可以理解为已经准备好了,要去拿蘸料的动作的父级。 * AllocatSeasoning可以理解为 蘸料和婉的合体。 */ public class AllocDecorator implements AllocatSeasoning{ // 持有对象 private AllocatSeasoning allocatSeasoning; // 构造器 public AllocDecorator(AllocatSeasoning allocatSeasoning) { this.allocatSeasoning = allocatSeasoning; } // 调用对下个对应的方法 @Override public void allo() { allocatSeasoning.allo(); } }
第四步:具体装饰器类
放具体的蘸料(ConcreteDecorator)这里说白了就是 拿着放有蘸料的碗(可以是空碗)来放现在想放的蘸料。我这里只给出了一个具体类,其他的有兴趣可以把代码复制,然后补充下。
/** * 具体装饰器类(ConcreteDecorator):该实现类要向被装饰的对象添加某些功能; * 这里说白了就是 拿着放有蘸料的碗(可以是空碗)来放现在想放的蘸料 */ public class GarlicAlloc extends AllocDecorator{ public GarlicAlloc(AllocatSeasoning allocatSeasoning) { super(allocatSeasoning); } @Override public void allo() { // 调用原有业务方法 super.allo(); // 补充我们这个行为的方法 addGarlic(); } public void addGarlic() { System.out.println("---加蒜---"); } }
测试类
public class DecoratorClinet { public static void main(String[] args) { AllocatSeasoning a = new OilAlloc(new GarlicAlloc(new ChilliAlloc(new AllocDo()))); a.allo(); } }
运行结果:
----- 您好,这边是调料自选区,可以按照您的口味选择自己喜欢的口味 ----- ---加辣椒--- ---加蒜--- ---加油--
装饰者模式优缺点
1.装饰者模式优点
装饰器是继承的有力补充,在不改变原有对象的情况下,比继承灵活;
通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果;
装饰器模式完全遵守开闭原则;
2.装饰者模式缺点
增加复杂度:装饰器模式会增加许多子类,过度使用会增加程序得复杂性;
装饰者模式小结
由于具体构件类和装饰类都实现了相同的抽象构件接口,因此装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任。
换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》