设计模式 结构型模式 -- 装饰者模式(概述 & 快餐店案例 & 模式优点 & 使用场景 & 源码解析 & 和代理模式的区别)

Posted Z && Y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式 结构型模式 -- 装饰者模式(概述 & 快餐店案例 & 模式优点 & 使用场景 & 源码解析 & 和代理模式的区别)相关的知识,希望对你有一定的参考价值。

1. 装饰者模式


1.1 概述

我们先来看一个快餐店的例子:

快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦。

使用继承的方式存在的问题:

  • 扩展性不好: 如果要再加一种配料(火腿肠),我们就会发现需要给FriedRice和FriedNoodles分别定义一个子类。如果要新增一个快餐品类(炒河粉)的话,就需要定义更多的子类(产生过多的子类)。

1.2 定义

指在不改变现有对象结构的情况(不需要创建更多的子类),动态地给该对象增加一些职责(即增加其额外功能)的模式。


1.3 结构

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

装饰者模式结构:


1.3.1 抽象构件类典型代码


1.3.2 具体构件类典型代码:


1.3.3 抽象装饰类典型代码:


1.3.4 具体装饰类典型代码:


1.4 实例说明:

实例类图:

说明:


1.5 快餐店案例改进: 装饰者模式

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

1.5.1 FastFood

package com.tian.decorator;

/**
 * @version v1.0
 * @ClassName: FastFood
 * @Description: 快餐类(抽象构件角色)
 */
public abstract class FastFood {

    private float price;//价格
    private String desc; //描述

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public FastFood(float price, String desc) {
        this.price = price;
        this.desc = desc;
    }

    public FastFood() {
    }

    public abstract float cost();
}

1.5.2 FriedRice

package com.tian.decorator;

/**
 * @version v1.0
 * @ClassName: FriedRice
 * @Description: 炒饭(具体构件角色)
 */
public class FriedRice extends FastFood {

    public FriedRice() {
        super(10, "炒饭");
    }

    public float cost() {
        return getPrice();
    }
}

1.5.3 FriedNoodles

package com.tian.decorator;

/**
 * @version v1.0
 * @ClassName: FriedNoodles
 * @Description: 炒面(具体的构件角色)
 */
public class FriedNoodles extends FastFood {

    public FriedNoodles() {
        super(12, "炒面");
    }

    public float cost() {
        return getPrice();
    }
}

1.5.4 Garnish

package com.tian.decorator;

/**
 * @version v1.0
 * @ClassName: Garnish
 * @Description: 装饰者类(抽象装饰者角色)
 */
public abstract class Garnish extends FastFood {

    //声明快餐类的变量
    private FastFood fastFood;

    public FastFood getFastFood() {
        return fastFood;
    }

    public void setFastFood(FastFood fastFood) {
        this.fastFood = fastFood;
    }

    public Garnish(FastFood fastFood, float price, String desc) {
        super(price, desc);
        this.fastFood = fastFood;
    }
}

1.5.5 Egg

package com.tian.decorator;

/**
 * @version v1.0
 * @ClassName: Egg
 * @Description: 鸡蛋类(具体的装饰者角色)
 */
public class Egg extends Garnish {

    public Egg(FastFood fastFood) {
        super(fastFood, 1, "鸡蛋");
    }

    public float cost() {
        //计算价格
        return getPrice() + getFastFood().cost();
    }

    @Override
    public String getDesc() {
        return super.getDesc() + getFastFood().getDesc();
    }
}

1.5.6 Bacon

package com.tian.decorator;

/**
 * @version v1.0
 * @ClassName: Egg
 * @Description: 培根类(具体的装饰者角色)
 */
public class Bacon extends Garnish {

    public Bacon(FastFood fastFood) {
        super(fastFood, 2, "培根");
    }

    public float cost() {
        //计算价格
        return getPrice() + getFastFood().cost();
    }

    @Override
    public String getDesc() {
        return super.getDesc() + getFastFood().getDesc();
    }
}

1.5.7 Client

package com.tian.decorator;

/**
 * @version v1.0
 * @ClassName: Client
 * @Description: 客户端类,测试类
 */
public class Client {
    public static void main(String[] args) {
        //点一份炒饭
        FastFood food = new FriedRice();

        System.out.println(food.getDesc() + "  " + food.cost() + "元");

        System.out.println("===============");

        //在上面的炒饭中加一个鸡蛋
        food = new Egg(food);
        System.out.println(food.getDesc() + "  " + food.cost() + "元");

        System.out.println("================");
        //再加一个鸡蛋
        food = new Egg(food);
        System.out.println(food.getDesc() + "  " + food.cost() + "元");

        System.out.println("================");
        food = new Bacon(food);
        System.out.println(food.getDesc() + "  " + food.cost() + "元");
    }
}

1.5.8 运行结果


1.6 装饰者模式优点


1.7 使用场景


1.7 JDK源码解析

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

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

类图:

小结:

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


1.8 代理模式和装饰者模式的区别



以上是关于设计模式 结构型模式 -- 装饰者模式(概述 & 快餐店案例 & 模式优点 & 使用场景 & 源码解析 & 和代理模式的区别)的主要内容,如果未能解决你的问题,请参考以下文章

Java设计模式之装饰者模式

设计模式 结构型模式 -- 结构型模式(代理模式适配器模式装饰者模式桥接模式外观模式组合模式享元模式)

设计模式结构型装饰者模式

从零开始学习Java设计模式 | 结构型模式篇:装饰者模式

从零开始学习Java设计模式 | 结构型模式篇:装饰者模式

聊一聊装饰者模式