装饰模式
公司的一些业务类最开始的设计只实现了核心功能,在后来不断的发展中,需要对其功能进行扩展,增加诸如缓存、加密等功能。为了符合开闭原则,不对原有类进行修改。如果通过新增类继承原有类的方式,类的数量将会成几何级上涨。例如原有3个类,现在要对这些类都扩展四个新功能。那最少就要增加12个子类。臃肿、麻烦。
装饰模式可以解决这个问题。
定义: 动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。
装饰模式引入装饰器,与被装饰者继承相同的抽象类,是客户端几乎透明的使用。这一点与代理模式相似。装饰器持有被装饰者的引用,可以调用原始的实现。在运行时,可以动态的设置这个引用,因此对于新增的一类功能,编写一个装饰器,即可对所有原始类进行装饰,解决了类的数量暴增的问题。同时,还可以实现嵌套多层装饰。结构如下:
Component为抽象父类。
ConcreteComponentt为具体实现。
Decorator为装饰器父类。
然后是具体装饰器。
Java代码实现:
public interface Worker { public void work(); } public class RealWorker implements Worker { @Override public void work() { System.out.println("working..."); } } public class Decotator implements Worker { private Worker worker; public Decotator(Worker worker) { this.worker = worker; } @Override public void work() { worker.work(); } } public class LogDecorator extends Decotator { public LogDecorator(Worker worker) { super(worker); } @Override public void work() { super.work(); log(); } public void log() { System.out.println("loging..."); } } public class test { public static void main(String[] args) { RealWorker worker = new RealWorker(); Decotator decorator = new LogDecorator(worker); decorator.work(); } }
输出:
working...
loging...
装饰模式与代理模式原理看起来非常相似,实际有很多区别。
- 代理模式通常用于对被代理对象的访问控制,而装饰模式用于对对象功能的增强。
- 代理用于对被代理的控制,所以通常替代被代理对象,在代理内部生成被代理示例,外部透明。而装饰器只是增强和装饰的作用。对象通常由外部传进来。
- 装饰器模式旨在动态的装饰,而代理模式在编写时就确定了代理 关系。(动态代理除外)
- 桥接模式行为和变化是横向的,彼此之间关联不大,而装饰模式行为和变化是纵向的,叠加起来组成完整的统一行为。
优点:
- 对已有类扩展,符合开闭,可以动态扩展,控制类的数量,提高代码重用。
- 可以嵌套装饰,比较灵活
- 具体实现和适配器可以独立变化和扩展,符合开闭
缺点:
- 更灵活,单更容易出错
- 不影响实现的前提下,透明动态的扩展功能。
- 用继承的方式扩展导致类数量暴增时。