Java设计模式之装饰者模式

装饰者模式

Decorator

装饰者模式(装饰模式)是一种结构型模式

在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能

它是通过创建一个包装对象,也就是装饰来包裹真实的对象

引入装饰者模式

项目需求: 有一家汉堡店,汉堡店里有卖汉堡和酱料,顾客可以只点汉堡也可以点汉堡+酱料,该如何设计结构

方案一

在这里插入图片描述

面向接口编程的思想 , 接口抽象套餐价格方法和套餐内容方法,让套餐实现类去实现方法

当汉堡或酱料很多时,不同的搭配有很多种 缺点: 会产生大量的类

方案二

在这里插入图片描述

将酱料充当抽象类的字段,抽象类中有设置某酱料(番茄酱,辣椒酱等…)数量的方法,汉堡则作为实现类去实现抽象类

缺点: 当要增加新酱料时,要改动抽象类,违反开闭原则

方案三

使用装饰者模式

装饰者模式角色

大话设计模式结构图

在这里插入图片描述

装饰者模式可以看成将一个主体一层一层包裹

比如客户要求: 鸡肉汉堡+番茄酱+辣椒酱

那么主体就是鸡肉汉堡,对酱料(包装)进行一层一层的包裹

在这里插入图片描述

主体被装饰者: Component, ConcreteComponent

装饰者(酱料): Decorator , ConcreteDecorator

把酱料一层一层裹在汉堡上 就是 装饰者模式

汉堡店例子使用装饰者模式

在这里插入图片描述

当ConcreteComponent很多都有共同点时,可以抽成一个缓冲层 (如图:很多汉堡抽成一个缓冲层,汉堡实现类去实现Hamburg抽象类)

装饰者模式代码

汉堡例子的装饰者模式代码

整体结构

在这里插入图片描述

Component

public abstract class Component {
    //成本
    private double money;
    //套餐内容描述
    private String description;

    protected String getDescription() {
        return description;
    }

    protected void setDescription(String description) {
        this.description = description;
    }

    protected double getMoney() {
        return money;
    }

    protected void setMoney(double money) {
        this.money = money;
    }

     /**
     * 价格
     */
    public abstract double price();

    /**
     * 套餐内容描述
     */
    public abstract String description();
}

ConcreteComponent

public  class Hamburg extends Component {

    @Override
    public double cost() {
        return getMoney();
    }

    @Override
    public String description() {
        return getDescription();
    }
}
public class ChickenHamburg extends Hamburg{
    public ChickenHamburg() {
        //设置价格为5
        setMoney(5);
        //设置套餐内容为鸡肉汉堡
        setDescription("鸡肉汉堡(5.0)");
    }
}
public class BeefHamburg extends Hamburg{
    public BeefHamburg() {
        //设置价格为16.5
        setMoney(16.5);
        //设置套餐内容为牛肉汉堡
        setDescription("牛肉汉堡(16.5)");
    }
}

Decorator

public class Decorator extends Component{
    protected Component component;
	//可以通过构造器设置Component
    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public double price() {
        //酱料的钱 + Component的钱 (一层一层包裹的Component)
        return getMoney() + component.getMoney();
    }

    @Override
    public String description() {
        //酱料套餐内容 + Component套餐内容 (一层一层包裹的Component)
        return getDescription() + " + " +component.description();
    }
}

ConcreteDecotator

public class ChiliSauce extends Decorator{
    public ChiliSauce(Component component) {
        super(component);
        setMoney(2.5);
        setDescription("辣椒酱");
    }
}
public class TomatoSauce extends Decorator {
    public TomatoSauce(Component component) {
        super(component);
        setMoney(1.5);
        setDescription("番茄酱(1.5)");
    }
}

汉堡店

public class HamburgStore {
    public static void main(String[] args) {
        //目标: 鸡肉汉堡加番茄酱加辣椒酱
        //1.主体:鸡肉汉堡(被装饰者)
        Component hamburg = new ChickenHamburg();
        System.out.println("描述: " + hamburg.description());
        System.out.println("成本: " + hamburg.price() + "元");
        System.out.println("==================================");
        //2.番茄酱 --装饰--> (鸡肉汉堡)   ==形成的Component==> (鸡肉汉堡+番茄酱)
        hamburg = new TomatoSauce(hamburg);
        System.out.println("描述: " + hamburg.description());
        System.out.println("成本: " + hamburg.price() + "元");
        System.out.println("==================================");
        //3.辣椒酱  --装饰--> (鸡肉汉堡+番茄酱) ==形成的Component==> (鸡肉汉堡+番茄酱+辣椒酱)
        hamburg = new ChiliSauce(hamburg);
        System.out.println("描述: " + hamburg.description());
        System.out.println("成本: " + hamburg.price() + "元");
        System.out.println("==================================");
    }
}
/*
描述: 鸡肉汉堡(5.0)
成本: 5.0元
==================================
描述: 番茄酱(1.5) + 鸡肉汉堡(5.0)
成本: 6.5元
==================================
描述: 辣椒酱 + 番茄酱(1.5) + 鸡肉汉堡(5.0)
成本: 4.0元
==================================
*/

核心: Decorator继承Component且聚合Component(字段有Component),这样使得每次装饰完都是Component整体,方便继续装饰

如果要增加新汉堡只需要继承Hamburg抽象层

如果要增加新酱料只需要继承Decorator

如果要增加新食品(鸡块,鸡腿等)只需要继承Component

不会违反开闭原则

JDK中的装饰模式

IO中的装饰模式

//类比 Component
public abstract class InputStream 
//FileInputStream继承自InputStream  类比ConcreteComponent(被装饰者 汉堡)
public class FileInputStream extends InputStream
//FilterInputStream继承自InputStream 并且 字段有InputStream(包含被装饰者) 类比Decorator
public class FilterInputStream extends InputStream {
    protected volatile InputStream in;
    //...
}    
//BufferedInputStream继承自FilterInputStream 类比ConcreteDecorator(装饰者 酱料)
public class BufferedInputStream extends FilterInputStream {

在这里插入图片描述

//BufferInputStream 对 FileInputStream 进行装饰 (装饰包裹这个对象 类似管道包裹在另一根管道上)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\asd.text"));

总结

与一开始的继承相比,它们都是为了扩展对象功能,但是装饰模式更加灵活且复杂

装饰模式: 动态的将新功能增加到对象上(装饰包裹这个对象)

特点

  • 装饰者 和 被装饰者 拥有共同的父类(或接口) Component

  • 装饰者 聚合(组合)了 被装饰者

    装饰者包含被装饰者的引用

    装饰者某个字段是被装饰者

  • 通过不同的装饰类与被装饰类排列组合,可以有很多不同行为功能的组合

使用场景

  • 需要动态的给对象增加功能还可以动态撤销功能
  • 取代 例子中使用继承的基本功能的排列组合
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值