设计模式---结构型---装饰器模式

什么是装饰器模式?

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
我们通过下面的实例来演示装饰器模式的用法。其中,我们将把一个形状装饰上不同的颜色,同时又不改变形状类。

普通示例

1.新建一个普通的蛋糕类

import java.math.BigDecimal;

public class Cake {
    public String getCakeMsg() {
        return "我是一个普通的蛋糕";
    }

    public BigDecimal getPrice() {
        return new BigDecimal("58");
    }
}

2.这个时候,我们需要给蛋糕加点芒果,那可以在再新建一个类去继承普通Cake类,然后重写其中的方法

import java.math.BigDecimal;

public class CakeAddMango extends Cake {
    @Override
    public String getCakeMsg() {
        return super.getCakeMsg()+"+2个芒果";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal("10"));
    }
}

3.这时候,如果不仅仅加芒果,还要在加点葡萄,那么可以在写一个类,继承CakeAddMango,让后重写其中的方法

import java.math.BigDecimal;

public class CakeAddMangoAddGrape extends CakeAddMango {
    @Override
    public String getCakeMsg() {
        return super.getCakeMsg()+"+1个葡萄";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal("5"));
    }
}

写个测试类测一下

 @Test
    public void test1() {
        // 1.普通的蛋糕
        Cake cake = new Cake();
        System.out.println(cake.getCakeMsg() + " 价格: " + cake.getPrice());

        // 2. 加芒果的蛋糕
        CakeAddMango cakeAddMango = new CakeAddMango();
        System.out.println(cakeAddMango.getCakeMsg()+" 价格: "+cakeAddMango.getPrice());

        // 3.加芒果和葡萄的当高
        CakeAddMangoAddGrape cakeAddMangoAddGrape = new CakeAddMangoAddGrape();
        System.out.println(cakeAddMangoAddGrape.getCakeMsg()+" 价格: "+cakeAddMangoAddGrape.getPrice());

    }

在这里插入图片描述
问题引入: 看起来挺好的,能实现,但是假如我们加4个芒果呢?或者我要加两个普通的葡萄呢?或者说芒果和葡萄要组合,数量不一定,那么利用现有的类时无法实现的,只能不断加类去重写,如果业务变的更麻烦,修改也是致命的
正因为普通的实现方法有这种缺陷,才有了装饰器模式,接下来我们用装饰器类实现上面的需求

装饰者模式示例

1.新建一个蛋糕的抽象类

package com.sth.spring.zsz;

import java.math.BigDecimal;

public abstract class Cake {
    public abstract String getCakeMsg();

    public abstract BigDecimal getPrice();
}

2.然后新建一个普通蛋糕的类

package com.sth.spring.zsz;

import java.math.BigDecimal;

public class BaseCake extends Cake {
    @Override
    public String getCakeMsg() {
        return "我是一个普通的蛋糕";
    }

    @Override
    public BigDecimal getPrice() {
        return new BigDecimal("58");
    }
}

3.新建一个蛋糕的装饰器类,内部持有蛋糕Cake对象,这个就是扩展的关键:

import java.math.BigDecimal;

public abstract class CakeDecorator extends Cake {
    private Cake cake;

    public CakeDecorator(Cake cake) {
        this.cake = cake;
    }

    @Override
    public String getCakeMsg() {
        return this.cake.getCakeMsg();
    }

    @Override
    public BigDecimal getPrice() {
        return this.cake.getPrice();
    }
}

4.新建一个芒果蛋糕的装饰器类继承CakeDecorator类:

import java.math.BigDecimal;

public class CakeAddMangoDecorator extends CakeDecorator {
    public CakeAddMangoDecorator(Cake cake) {
        super(cake);
    }

    @Override
    public String getCakeMsg() {
        return super.getCakeMsg() + "+2个芒果";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal("10"));
    }
}

5.新建一个葡萄蛋糕的装饰器类继承CakeDecorator类:

import java.math.BigDecimal;

public class CakeAddGrapDecorator extends CakeDecorator {
    public CakeAddGrapDecorator(Cake cake) {
        super(cake);
    }

    @Override
    public String getCakeMsg() {
        return super.getCakeMsg() + "+1个葡萄";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal("5"));
    }
}

6.最后写一个测试类测试一下

 @Test
    public void test1() {
       Cake cake=null;
       // 普通蛋糕
        cake=new BaseCake();
        System.out.println(cake.getCakeMsg()+"价格: "+cake.getPrice());

        // 加2个芒果
        cake= new CakeAddMangoDecorator(cake);
        System.out.println(cake.getCakeMsg()+"价格: "+cake.getPrice());
        // 加一个葡萄
        cake = new CakeAddGrapDecorator(cake);
        System.out.println(cake.getCakeMsg()+"价格: "+cake.getPrice());

        // 再加2个芒果
        cake= new CakeAddMangoDecorator(cake);
        System.out.println(cake.getCakeMsg()+"价格: "+cake.getPrice());
    }

在这里插入图片描述
我们现在可以看到,使用装饰器模式之后,扩展之前的功能变的极为方便,可以根据现有的装饰器进行任意组合

类关系图

看一下类图,首先是一个基础抽象类定义了基本的方法,然后是基础实现和基础装饰器继承并重写抽象类的方法:
在这里插入图片描述

装饰器模式的使用场景

  1. 用于扩展一个类的功能or給一个类添加附加职责
  2. 动态的该一个对象添加功能,这些功能可以动态的撤销
    **注:**Mybatis中的二级缓存就是装饰器模式来进行动态扩展.

装饰器模式的优点

  1. 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地給一个对象扩展功能,即插即用
  2. 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同的效果
  3. 装饰器完全遵守开闭原则

装饰器模式的缺点

  1. 会出现更多的代码,更多的类,增加程序的复杂性
  2. 动态装饰以及多层装饰时会更加复杂

菜鸟教程中的装饰器模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值