软件设计模式--第三章 结构型模式--装饰者模式


第三章 结构型模式

1、结构型模式概述

结构型模式描述如何将类或对象按某种布局组成更大的结构。

  • 类结构型模式:采用继承机制来组织接口和类,
  • 对象结构型模式:采用组合或聚合来组合对象。
  • 由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

结构型模式分为以下7种:

  1. 代理(Proxy)模式:客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。

  2. 适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

  3. 桥接(Bridge)模式:将抽象与实现分离,使他们可以独立的变化。用组合关系代替继承关系来实现,从而降低了抽象和实现这2个可变维度的耦合度。

  4. 装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。

  5. 外观(Facade)模式:为多个复杂的子系统提供一个一致的接口, 使这些子系统更加容易被访问。

  6. 享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度 对象的复用

  7. 组合(Composite)模式将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。

注:以上7种结构型模式,除了适配器模式分为类结构型模式和对象结构型模式2种,其他的全部属于对象结构型模式。

2、装饰者模式

(1)模式的定义与特点

  1. 定义:
    指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。

  2. 优点:

    • 采用装饰模式扩展对象的功能比采用继承方式更加灵活
    • 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。

3. 缺点:装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。

(2)模式的结构与实现

  1. 结构
  • 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  • 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

结构图如下:
在这里插入图片描述

在这里插入图片描述

  1. 实现

例:设计一个“人”类,再使用装饰模式赋予“人”类更强大的本领如“天上飞”、“水下游”以及“力如牛”等而成为“超人”

在这里插入图片描述

抽象构件角色:人类接口

// 抽象构件:人类接口,定义了人的规范
public interface Human {
    // 人具有的能力
    void ability();
}


具体构件角色:人会说话写字

// 具体构件,人会说话,写字
public class man implements Human {

    @Override
    public void ability() {
        System.out.println("说话,写字");
    }
}

抽象装饰者角色:超能力

// 抽象装饰者:超能力
public class Powers implements Human {

    // 聚合人类
    Human human;

    public Powers(Human human) {
        this.human = human;
    }

    @Override
    public void ability() {
        // 人类原有的能力
        human.ability();
    }
}

具体装饰者角色:天上飞的能力

// 具体装饰者:天上飞的能力
public class Fly extends Powers{

    public Fly(Human human) {
        super(human);
    }
    // 增加超能力
    public void ability() {

        // 1. 原来的能力
        super.ability();
        // 2. 增加能力
        setFly();

    }
    public void setFly(){
        System.out.println("天上飞");
    }
}


具体装饰者角色:水上游

// 具体装饰者:水上游的能力
public class Water extends Powers{
    
    public Water(Human human) {
        super(human);
    }
    // 增加超能力
    public void ability() {

        // 1. 原来的能力
        super.ability();
        // 2. 增加能力
        setWater();

    }
    public void setWater(){
        System.out.println("水上游");
    }
    
}

​具体装饰者角色:力如牛

// 具体装饰者:力如牛的能力
public class Cattle extends Powers{

    public Cattle(Human human) {
        super(human);
    }
    // 增加超能力
    public void ability() {

        // 1. 原来的能力
        super.ability();
        // 2. 增加能力
        setCattle();

    }
    public void setCattle(){
        System.out.println("力如牛");
    }
}

测试类

public class Client {
    public static void main(String[] args) {

        // 1. 创建人类,
        Human human=new man();
        // 2.此时具有的能力有
        System.out.println("man 此时有的能力有:");
        human.ability();
        System.out.println("============");

        // 3. 增加超能力fly
        System.out.println("man 此时有的能力有:");
        human=new Fly(human);
        human.ability();
        System.out.println("============");

        // 4. 增加能力water
        System.out.println("man 此时有的能力有:");
        human=new Water(human);
        human.ability();

        // 5.增加能力cattle
        System.out.println("man 此时有的能力有:");
        human=new Cattle(human);
        human.ability();
       
    }
}

在这里插入图片描述

(3)应用场景

  1. 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

  2. 不能采用继承的情况主要有两类:

    • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类定义不能继承(如final类)
  3. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  4. 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

(4)扩展

(1)JDK源码解析

IO流中的包装类使用到了装饰者模式。BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter

我们以BufferedWriter举例来说明,先看看如何使用BufferedWriter


public class Demo {
    public static void main(String[] args) throws Exception{
        //创建BufferedWriter对象
        //创建FileWriter对象
        FileWriter fw = new FileWriter("C:\\Users\\Think\\Desktop\\a.txt");
        BufferedWriter bw = new BufferedWriter(fw);//写数据
        bw.write("hello Buffered");
​
        bw.close();
    }
}

结构:装饰者模式的精髓就是子类继承的同时再聚合在这里插入图片描述

BufferedWriter使用装饰者模式对Writer子实现类进行了增强,添加了缓冲区,提高了写数据的效率

(2)代理和装饰者的区别
  • 相同点:

    • 都要实现与目标类相同的业务接口
    • 在两个类中都要声明目标对象
    • 都可以在不修改目标类的前提下增强目标方法
  • 不同点:

    • 目的不同
      装饰者是为了增强目标对象
      静态代理是为了保护和隐藏目标对象
    • 获取目标对象构建的地方不同
      装饰者是由外界传递进来,可以通过构造方法传递
      静态代理是在代理类内部创建,以此来隐藏目标对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绿箭柠檬茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值