【概念】
装饰者模式:
动态地将责任附加到对象上,若要扩展对象,装饰者模式提供了比继承更弹性的替代方案
要点:装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为
装饰者包含一个超类的对象,这样,可以在被装饰者行为前或者行为后加上新的行为,甚至取代原有的行为
装饰者会使程序中出现很多小类,增加使用难度
使用场景:对象由主体+许多可选的部件或者功能构成,使用继承或者接口会产生很多类,且很难扩展。
【原则】
1. 多用组合,少用继承。
利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。
2. 类应设计的对扩展开放,对修改关闭。
【实现图解】
模式的简化:
1. 如果只有一个Concrete Component类而没有抽象的Component接口时,可以让Decorator继承Concrete Component。
2. 如果只有一个Concrete Decorator类时,可以将Decorator和Concrete Decorator合并。
【装饰模式实例与代码实现:】
手机超类:
- <span style="font-size:14px;">
- public interface Phone {
- public abstract void call();
- }</span>
具体的手机类:
- <span style="font-size:14px;">public class PhoneImpl implements Phone {
-
- @Override
- public void call() {
- System.out.println("用手机打电话");
- }
-
- }</span>
抽象装饰类:
- <span style="font-size:14px;">public abstract class PhoneDecorate implements Phone {
-
- private Phone phone;
-
- public PhoneDecorate(Phone phone) {
-
-
- this.phone = phone;
- }
- @Override
- public void call() {
- this.phone.call();
- }
- }</span>
具体装饰类:彩铃装饰类:
- <span style="font-size:14px;">public class ColorPhoneDecorate extends PhoneDecorate {
-
- public ColorPhoneDecorate(Phone phone) {
-
- super(phone);
- }
-
- @Override
- public void call() {
- System.out.println("播放彩铃");
- super.call();
- }
- }</span>
具体装饰类:广告装饰类:
- <span style="font-size:14px;">public class GuangGaoPhoneDecorate extends PhoneDecorate {
-
- public GuangGaoPhoneDecorate(Phone phone) {
- super(phone);
- }
-
- @Override
- public void call() {
- super.call();
- System.out.println("播放广告");
- }
- }</span>
测试类:
- <span style="font-size:14px;">public class PhoneTest {
- public static void main(String[] args) {
-
- Phone p = new PhoneImpl();
- p.call();
-
- PhoneDecorate pd = new ColorPhoneDecorate(p);
- pd.call();
-
- pd = new GuangGaoPhoneDecorate(p);
- pd.call();
-
- pd = new GuangGaoPhoneDecorate(new ColorPhoneDecorate(p));
- pd.call();
- }
- }</span>
可以看出,修饰模式总共有四部分组成,1)抽象被修饰类或接口;2)具体被修饰类;3)抽象修饰类;4)具体修饰类。
装饰者模式在JDK中的运用
Java当中的IO是运用了装饰者模式的最典型的例子。
下面是一个简单的例子,通过BufferedReader对象来装饰InputStreamReader对象
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));