持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情。
装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
多用组合少用继承(不重写父类方法)
简单装饰器
当具体构建唯一的时候,如果我们想对其功能进行扩展的时候,可以使用简单装饰器模式。
角色
- 具体构件 (需要被装饰的角色)
- 抽象装饰器 (为装饰器定义抽象)
- 具体装饰器 (抽象装饰器的实现)
其实若装饰器也唯一,则可以去掉抽象装饰器
实现
定义具体构件
public class BaseComponent {
public void method(){
System.out.println(BaseComponent.class.getName());
}
}
定义装饰器接口(也可以使用抽象类)
其中存在一个和具体构件同名的方法,和其他装饰方法(或者叫扩展方法)
public interface IDecorator {
/**
* 抽象方法命名一般和具体构建方法一致
*/
void method();
/**
* 装饰抽象方法
*/
void decorateBefore();
/**
* 装饰抽象方法
*/
void decorateAfter();
}
定义具体装饰器
public class Decorator1 implements IComponent, IDecorator {
/**
* 组合构件
*/
private IComponent iComponent;
public Decorator1(IComponent iComponent) {
this.iComponent = iComponent;
}
@Override
public void method() {
this.decorateBefore();
iComponent.method();
this.decorateAfter();
}
@Override
public void decorateBefore() {
System.out.println(this.getClass().getName() + "<>" + "before");
}
@Override
public void decorateAfter() {
System.out.println(this.getClass().getName() + "<>" + "before");
}
}
测试
public class DecoratorTest {
@Test
public void decoratorTest(){
//具体构建
BaseComponent baseComponent = new BaseComponent();
//定义装饰器
IDecorator simpleDecorator = new SimpleDecorator(baseComponent);
simpleDecorator.method();
}
}
思考
简单装饰器模式其装饰的是一个具体构件,如果说需要在现有装饰器基础上扩展其他方法,需要重写一个装饰器且不能复用现有装饰器逻辑,使得代码冗余扩展性差。
在java中对一个类进行拓展可以采用继承的方式,同样也可以达到我们想要的目的。那为何使用装饰器模式而摒弃继承呢?对于简单装饰器确实没有太大区别,两者的扩展性都不好。但是装饰器模式是符合开闭原则的,而继承是侵入式的。
透明化装饰器
装饰器模式是对构件的拓展,不可避免的声明拓展方法。装饰器模式的透明化要求客户端声明抽象构件的引用,而不是一个具体构件。
透明化装饰器模式要求装饰器对客户端隐藏装饰实现。
要求装饰器和构件实现同一接口。
角色
- 抽象构建 (抽象构建)
- 具体构件 (需要被装饰的角色)
- 抽象装饰器
- 具体抽象器 (抽象装饰器的实现)
实现
定义抽象构件
public interface IComponent {
/**
* method
*/
void method();
}
定义具体构建
public class Component01 implements IComponent {
@Override
public void method() {
System.out.println(this.getClass().getName());
}
}
定义抽象装饰器
public interface IDecorator {
/**
* 装饰抽象方法
*/
void decorateBefore();
/**
* 装饰抽象方法
*/
void decorateAfter();
}
定义具体装饰器
public class Decorator1 implements IComponent, IDecorator {
/**
* 组合构件
*/
private IComponent iComponent;
public Decorator1(IComponent iComponent) {
this.iComponent = iComponent;
}
@Override
public void method() {
this.decorateBefore();
iComponent.method();
this.decorateAfter();
}
@Override
public void decorateBefore() {
System.out.println(this.getClass().getName() + "<>" + "before");
}
@Override
public void decorateAfter() {
System.out.println(this.getClass().getName() + "<>" + "before");
}
}
测试
由于我们这边组合的是抽象构件,所以此装饰器可以装饰一类对象
public class Component02 implements IComponent {
@Override
public void method() {
System.out.println(this.getClass().getName());
}
}
测试
/**
* 此装饰器可以装饰实现IComponent接口的所有构件
*/
@Test
public void test02(){
//具体构件
IComponent component02 = new Component02();
//视为IComponent
IComponent decorator1 = new Decorator1(component02);
decorator1.method();
}
还有装饰器同时实现了抽象构件接口和抽象装饰器接口,所以装饰器也可以被装饰器装饰,达到代码复用、降低冗余的目的。
再定义一个装饰器:
public class Decorator2 implements IComponent, IDecorator {
/**
* 组合构件
*/
private IComponent iComponent;
public Decorator2(IComponent iComponent) {
this.iComponent = iComponent;
}
@Override
public void method() {
this.decorateBefore();
iComponent.method();
this.decorateAfter();
}
@Override
public void decorateBefore() {
System.out.println(this.getClass().getName() + "<>" + "before");
}
@Override
public void decorateAfter() {
System.out.println(this.getClass().getName() + "<>" + "before");
}
}
测试:
/**
* 因为装饰器也实现了抽象构件接口,所以装饰器也可以装饰装饰器,达到复用目的
*/
@Test
public void test03(){
//具体构件
IComponent component02 = new Component02();
//视为IComponent
IComponent decorator1 = new Decorator1(component02);
decorator1.method();
System.out.println("<+++++++++++++++++++++>");
IComponent decorator2 = new Decorator2(decorator1);
decorator2.method();
}
这里类似一个环绕通知
装饰器模式 & 继承
- 透明化的装饰器模式完全遵守开闭原则,而继承是侵入式的,且不易扩展
- 透明化装饰器可以动态的对一个对象做扩展,而继承是静态的