DecoratorMode

java 装饰器模式

结构

模式结构

AruOFU.md.png

  • Component抽象构件角色:真实对象和装饰对象有相同的接口。这样,客户端对象就能够以与真实对象相同的方式同装饰对象交互。
  • ConcreteCompoent具体构建角色(真实对象):定义一个将要接收附加责任的类。
  • Decorator装饰角色:持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能。
  • ConcreteDecorate具体装饰角色:负责给构件对象增加新的功能。

代码结构:

AruXYF.png

代码

Person.java

Component抽象构件角色:

​ 就是一个功能接口

1
2
3
4
5
6
package com.user;

public interface Person {
void eat();

}

Man.java

ConcreteCompoent具体构建角色(真实对象):

​ 定义具体要被装饰的类(Man),这个类要实现上述接口(实现eat)

1
2
3
4
5
6
7
8
9
10
11
package com.user;

public class Man implements Person {

@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("男人在吃饭");
}

}

Decorator.java

Decorator装饰角色:

​ 持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.user;

public abstract class Decorator implements Person {

Person person; // 持有接口的引用 加不加protected 都行 如果为了安全还是加上好
public Decorator(Person person) // 将原里的set函数改为构造函数
{
this.person = person;
}
@Override
public void eat() {
// TODO Auto-generated method stub
person.eat();
}

}

​ 这个装饰器持有抽象接口(Person)的对象,并通过构造函数对它初始化,抽象装饰器也要实现步骤1中的抽象接口(Person),只不过抽象装饰器的实现方式比较特殊,它通过调用持有的抽象接口(Person)的对象的方法来实现抽象接口的功能函数。

​ 那么算是一个接口的对象呢? 具体来说就是实现了这个接口的所有类,都可以实例化出一个对象来作为接口的对象,比如 Man me = new Man(); 因为Man 实现了 Person接口所以me 就是一个接口(Person)对象,所以把me 传递到具体装饰角色DecoratorA(Person person)的构造函数里不会报错。

DecoratorA.java

ConcreteDecorate具体装饰角色:

​ 负责给构件对象增加新的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.user;

public class DecoratorA extends Decorator { // 具体的装饰器 继承 抽象的装饰器

public DecoratorA(Person person) {
super(person); // 调用父类构造函数的 this.person = person
}
public void Aeat(){
// eat 的包装新功能
System.out.println("Eat A Balabala");
}
@Override
public void eat(){
super.eat(); // 调用父类的eat()函数
Aeat(); // 执行Aeat()函数包装的新功能
}
}

DecoratorB.java

ConcreteDecorate具体装饰角色:

​ 负责给构件对象增加新的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.user;

public class DecoratorB extends Decorator { // 具体的装饰器 继承 抽象的装饰器
public DecoratorB(Person person) {
super(person); //调用父类构造函数的 this.person = person
}
public void eatB(){
// eat 的另一种包装新功能
System.out.println("eat B balabala");
}
@Override
public void eat(){
super.eat();
eatB(); // 执行eat另一种包装新功能
}

}

总结

装饰器步骤:

  1. 定义要被装饰的功能(eat)抽象接口(Person)
  2. 定义具体要被装饰的类(Man),这个类要实现上述接口(实现eat)
  3. 定义抽象装饰器(Decorator),这个装饰器持有步骤1中的抽象接口(Person)的对象,并通过构造函数对它初始化,抽象装饰器也要实现步骤1中的抽象接口(Person),只不过 抽象装饰器的实现方式比较特殊,它通过调用持有的抽象接口(Person)的对象的方法来实现抽象接口的功能函数。 什么算是一个接口的对象呢? 具体来说就是实现了这个接口的所有类,都可以实例化出一个对象来作为接口的对象,比如 Man me = new Man(); 因为Man 实现了 Person接口 所以me 就是一个接口(Person)对象,所以把me 传递到DecoratorA(Person person)的构造函数里不会报错~
  4. 定义具体装饰器(DecoratorA/B/C…),包装功能函数eat,在super的基础上添加新功能。

优缺点

优点

  • 为类添加新的功能 但是 Man这个类却不用改变,也不会产生新的继承类,类的数目会比较少
  • 可以对一个对象进行多次装饰,创造出不同的表现

缺点

  • 产生一堆装饰器对象 比如这里的DecoratorA da、DecoratorB db稍微占用内存空间
  • 装饰模式易出错,调试排查比较麻烦。
感谢您的阅读,本文由 Space-X 版权所有。如若转载,请注明出处:Space-X(https://spaces-x.github.io/2019/03/31/DecoratorMode/
Algorithm1
Memory Paging