Java设计模式——03装饰者模式

一、装饰者模式基本介绍

1、什么是装饰者模式

装饰模式(Decorator)指的是在不改变原类文件和不使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

2、装饰者模式的优缺点

优点:

  1. 装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
  2. 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
  3. 装饰者模式有很好地可扩展性

缺点:

  1. 这种比继承更加灵活机动的特性,也同时意味着更多的复杂性
  2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂
  3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

3、使用场景

以下情况使用Decorator模式:

1. 需要扩展一个类的功能,或给一个类添加附加职责。

2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

4、装饰者模式的类图Java设计模式——03装饰者模式

在装饰模式中的各个角色有:
  (1)抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
  (2)具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
  (3)装饰(Decorator)角色:持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。
  (4)具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。

二、装饰者模式的实现

1、需求描述

沙发可以坐、可以躺,我们还可以为它添加上按摩功能使它成为保健沙发,我们还可以为它添加上可以展开供人睡觉的功能让它变成沙发床。(关于直接使用继承方法,导致“类爆炸”问题,可以参考https://www.cnblogs.com/rookieFly-tdiitd/p/4914593.html

2、具体实现

                                                                                                     类图

Java设计模式——03装饰者模式

(1)抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。

package 装饰者模式;
//抽象构件(Component)角色
public interface Component_Sofa {
    //测试方法,用以展示沙发所具有的功能
     void show();
     //坐
    void sit();
    //躺
    void lie();
}

 (2)具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。

package 装饰者模式;

/**
 * 再定义一个Sofa接口的实现类,扮演装饰模式中的
 *  具体构件(Concrete Component)角色
 */
public class ConcreteComponent_Sofa implements Component_Sofa {
    @Override
    public void show() {
        this.sit();
        this.lie();
    }

    @Override
    public void sit() {
        System.out.println("可以坐");
    }

    @Override
    public void lie() {
        System.out.println("可以躺");
    }
}

(3)装饰(Decorator)角色:持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。

package 装饰者模式;

/**
 * 再定义一个装饰(Decorator)角色
 * 持有一个构件(Component)对象的实例,
 * 并实现一个与抽象构件接口一致的接口
 */
public class Decorator_Sofa implements Component_Sofa {
    //私有的构件对象
    private Component_Sofa sofa;

    public Decorator_Sofa(Component_Sofa sofa) {
        this.sofa = sofa;
    }
    @Override
    public void show() {
        // 委派给具体构件
        sofa.show();
    }

    @Override
    public void sit() {
        // 委派给具体构件
        sofa.sit();
    }

    @Override
    public void lie() {
        // 委派给具体构件
        sofa.lie();
    }
}

(4)具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。

角色1:

package 装饰者模式;

/**
 * 具体装饰(Concrete Decorator)角色:负责给构件对象添加上新功能。
 */
public class ConcreteDecorator_Bedsofa extends Decorator_Sofa {

    public ConcreteDecorator_Bedsofa(Component_Sofa componentSofa) {
        super(componentSofa);
    }
    @Override
     public void show(){
        super.show();
        this.add();
    }
    void add(){
        System.out.println("可以睡觉");
    }

}

角色2: 

package 装饰者模式;

public class ConcreteDecorator_Healthsofa extends Decorator_Sofa {
    public ConcreteDecorator_Healthsofa(Component_Sofa sofa) {
        super(sofa);
    }

    @Override
    public void show() {
        super.show();
        this.add();
    }
     void add(){
        System.out.println("可以按摩");
    }
}

功能测试: 

package 装饰者模式;

public class Sofa_Test {
    public static void main(String[] args) {
        //1、普通沙发
        ConcreteComponent_Sofa sofa1 = new ConcreteComponent_Sofa();
        System.out.println("普通沙发功能:");
        sofa1.show();
        System.out.println();

        //2、BedSofa
        ConcreteDecorator_Bedsofa bedsofa = new ConcreteDecorator_Bedsofa(sofa1);
        System.out.println("Bed沙发功能:");
        bedsofa.show();
        System.out.println();

        //3、HealthSofa
        ConcreteDecorator_Healthsofa healthsofa = new ConcreteDecorator_Healthsofa(sofa1);
        System.out.println("Health沙发的功能");
        healthsofa.show();
        System.out.println();

    }
}

 运行结果:

普通沙发功能:
可以坐
可以躺

Bed沙发功能:
可以坐
可以躺
可以睡觉

Health沙发的功能
可以坐
可以躺
可以按摩


Process finished with exit code 0
 

 3、总结

装饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,装饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。

意图:动态地给一个对象添加一些额外的职责和增加功能。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
如何解决:将具体功能职责划分,同时继承装饰者模式。
关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。

 

参考文档1:https://baike.baidu.com/item/%E8%A3%85%E9%A5%B0%E6%A8%A1%E5%BC%8F/10158540?fr=aladdin

参考文档2:https://www.cnblogs.com/zhili/p/DecoratorPattern.html

参考文档3:https://www.cnblogs.com/jajian/p/9729989.html(汽车例子)

参考文档4(次重点):https://blog.csdn.net/qian520ao/article/details/82529890(美颜例子,可以不错)

参考文档5(次重点):https://www.cnblogs.com/rookieFly-tdiitd/p/4914593.html(豆浆加价例子)

参考文档5(主重点):http://www.cnblogs.com/java-my-life/archive/2012/04/20/2455726.html(设计模式在JAVA I/O库中的应用)