设计模式-装饰者模式

一、装饰者模式(结构型模式)
1.定义

装饰者模式(Decorator Pattern)是指在不改变原有对象的基础上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能,它通过创建一个包装对象,也就是装饰来包裹真实的对象)。
2.装饰者模式角色
**(1).抽象构件(Component):**通常是一个抽象类或者一个接口,定义了一系列方法,方法的实现可以由子类实现或者自己实现。通常不会直接使用该类,而是通过继承或者实现接口来实现特定的功能。
**(2).具体构件(Concrete Component):**是抽象构件(Component)的子类,实现了对应的方法,它就是那个被装饰的类。
**(3).抽象装饰者(Decorator):**是Component的子类,它是具体装饰者角色共同实现的类(可以是接口、抽象类、类),并且持有一个Comonent类型的对象引用,它的主要作用就是把客户端的调用委派到被装饰类。
**(4).具体装饰角色(Concrete Component):**它是具体的装饰类,是Decorator的子类,当然也是Component的子类。它主要就是定义具体的装饰功能。
3.代码实现方式
(1).创建一个抽象构件接口,定义一些方法。
(2).创建具体构件实现抽象构件,重写抽象构件中的方法(实现具体功能),这个具体构件就是基础构件了,也就是被装饰的类。
(3).创建抽象装饰者实现抽象构件,重写抽象构件中的方法,组合依赖一个抽象构件类型对象。
(4).创建具体构件继承(或实现)抽象装饰者,重写抽象装饰者中的方法,在重写的方法中调用组合的抽象构件类型角色的方法,然后再加上需要修饰的方法。
4.代码实现
(1).场景

比如我们做一个蛋糕,里面可以加一些水果啊,巧克力啥的。
(2).具体代码

package com.tw.designPattern.decorator.cake;

import java.math.BigDecimal;

/**
 * 抽象构件
 */
public interface Cake {

    String getCakeDesc();

    BigDecimal getPrice();
}

package com.tw.designPattern.decorator.cake;

import java.math.BigDecimal;

/**
 * 具体构件(基础构件)
 */
public class CommonCake implements Cake{

    @Override
    public String getCakeDesc() {
        return "这是一个普通蛋糕!";
    }

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

package com.tw.designPattern.decorator.cake;

import java.math.BigDecimal;

/**
 * 抽象装饰者
 */
public class Decorator implements Cake{

    private Cake cake;

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

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

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

package com.tw.designPattern.decorator.cake;

import java.math.BigDecimal;

/**
 * 具体装饰者
 */
public class MangoCakeDecorator extends Decorator{

    public MangoCakeDecorator(Cake cake) {
        super(cake);
    }

    @Override
    public String getCakeDesc(){
        return super.getCakeDesc() + "加一个芒果!";
    }

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

package com.tw.designPattern.decorator.cake;

import java.math.BigDecimal;

/**
 * 具体装饰者
 */
public class GrapesCakeDecorator extends Decorator{

    public GrapesCakeDecorator(Cake cake) {
        super(cake);
    }

    @Override
    public String getCakeDesc(){
        return super.getCakeDesc() + "加一个葡萄!";
    }

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

package com.tw.designPattern.decorator.cake;

public class DecoratorTest {

    public static void main(String[] args) {
        Cake cake = new CommonCake();
        cake = new Decorator(cake);
        System.out.println(cake.getCakeDesc() + " 价格: " + cake.getPrice());
        cake = new MangoCakeDecorator(cake);
        System.out.println(cake.getCakeDesc() + " 价格: " + cake.getPrice());
        cake = new MangoCakeDecorator(cake);
        System.out.println(cake.getCakeDesc() + " 价格: " + cake.getPrice());
        cake = new GrapesCakeDecorator(cake);
        System.out.println(cake.getCakeDesc() + " 价格: " + cake.getPrice());
    }
}

测试结果

这是一个普通蛋糕! 价格: 100
这是一个普通蛋糕!加一个芒果! 价格: 125
这是一个普通蛋糕!加一个芒果!加一个芒果! 价格: 150
这是一个普通蛋糕!加一个芒果!加一个芒果!加一个葡萄! 价格: 180

(3).装饰者对象结构
在这里插入图片描述
(4).具体代码2(如果上面这个super.getDesc()这样不好理解的话可以看下下面这个,是等价的。)

package com.tw.designPattern.decorator.cake1;

import java.math.BigDecimal;

/**
 * 抽象构件
 */
public interface Cake {

    String getCakeDesc();

    BigDecimal getPrice();
}

package com.tw.designPattern.decorator.cake1;

import java.math.BigDecimal;

/**
 * 具体构件(基础构件)
 */
public class CommonCake implements Cake {

    @Override
    public String getCakeDesc() {
        return "这是一个普通蛋糕!";
    }

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

package com.tw.designPattern.decorator.cake1;

import java.math.BigDecimal;

/**
 * 抽象装饰者
 */
public interface Decorator extends Cake {


    @Override
    String getCakeDesc();

    @Override
    BigDecimal getPrice();
}

package com.tw.designPattern.decorator.cake1;

import java.math.BigDecimal;

/**
 * 具体装饰者
 */
public class MangoCakeDecorator implements Decorator {

    private Cake cake;

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

    @Override
    public String getCakeDesc(){
        return this.cake.getCakeDesc() + "加一个芒果!";
    }

    @Override
    public BigDecimal getPrice(){
        return this.cake.getPrice().add(new BigDecimal("25"));
    }
}

package com.tw.designPattern.decorator.cake1;

import java.math.BigDecimal;

/**
 * 具体装饰者
 */
public class GrapesCakeDecorator implements Decorator {

    private Cake cake;

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

    @Override
    public String getCakeDesc(){
        return this.cake.getCakeDesc() + "加一个葡萄!";
    }

    @Override
    public BigDecimal getPrice(){
        return this.cake.getPrice().add(new BigDecimal("30"));
    }
}

package com.tw.designPattern.decorator.cake1;



public class DecoratorTest {

    public static void main(String[] args) {
        Cake cake = new CommonCake();
        System.out.println(cake.getCakeDesc() + " 价格: " + cake.getPrice());
        cake = new MangoCakeDecorator(cake);
        System.out.println(cake.getCakeDesc() + " 价格: " + cake.getPrice());
        cake = new MangoCakeDecorator(cake);
        System.out.println(cake.getCakeDesc() + " 价格: " + cake.getPrice());
        cake = new GrapesCakeDecorator(cake);
        System.out.println(cake.getCakeDesc() + " 价格: " + cake.getPrice());
    }
}

测试结果

这是一个普通蛋糕! 价格: 100
这是一个普通蛋糕!加一个芒果! 价格: 125
这是一个普通蛋糕!加一个芒果!加一个芒果! 价格: 150
这是一个普通蛋糕!加一个芒果!加一个芒果!加一个葡萄! 价格: 180

装饰者模式对象结构
在这里插入图片描述
这种代码执行方式类似递归调用那种感觉,(因为你会发现装饰者模式本来就是递归构造来实现组合嵌套的)一个Cake里面组合另一个Cake然后方法里面不是调用的是组合依赖的Cake的方法,然后再加点修改时么,那它就按这种结构一层一层的由外向内的调用,最后到基础构件了,有返回结果了,然后结果在由内向外一层一层的返回。这是我的个人理解啊,如果有不对的地方,还请指出,互相学习么。(也许等我后面牛逼了,我会回来改了这个理解。)
5.优缺点
(1).优点

(1-1).装饰者是继承的有利补充,比继承灵活,不改变原有对象的情况下动态的给一个对象扩展功能,即插即用。
(1-2).通过不同的装饰类以及装饰类的排列组合,实现不同效果。
(1-3).符合开闭原则
(2).缺点
(2-1).动态装饰以及多层装饰时会变得复杂,不太好理解
6.应用场景
(1).用于动态的扩展一个类的功能或给一个类添加附加职责。
7.我所了解的装饰器源码
(1).Java中的IO流中的FilterInputStream(FilterOutputStream)用的就是装饰者模式,写法和第一种的一样。
(2).Mybatis中的二级缓存。
应该还有很多,不过我就了解这两个,有兴趣可以去看一下人家的代码,认真看的话会有收获的。
8.装饰者模式与代理模式的区别与联系
(1).使用场景的区别

(1-1).代理模式侧重的时对对象行为的特殊控制,不同的代理对象实现对被代理对象行为的不同的控制,并且这些代理的行为控制很少有组合的可能性。
(1-2).装饰者模式侧重于对被装饰者对象属性(成员变量、成员方法)的扩展,不同的装饰者对象会为被装饰者对象添加不同的属性,并且这些属性可以任意嵌套组合。
(2).模式实现区别
(2-1).装饰者模式需要提供装饰对象为参数的构造函数,而代理对象则不需要,主要原因的装饰者模式需要支持嵌套组合属性。
(3).联系
(3-1).这两种模式都是通过实现真实对象的接口,并且组合依赖一个真是对象,通过操作改真实对象来实现具体功能。
注:内容参考网络上各种资料,还有一些本人的理解和思想,仅为了学习记录和分享一下自己所学之处,如有不足的地方麻烦大牛指出,如有侵权的地方,请联系删除,谢谢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值