ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

装饰者模式

2020-11-24 10:34:42  阅读:184  来源: 互联网

标签:BigDecimal getCakeMsg 模式 public cake getPrice 装饰


1.什么是装饰者模式

动态给对象增加功能,从一个对象的外部来给对象添加功能,相当于改变了对象的外观,比用继承的方式更加的灵活。

当使用装饰后,从外部系统的角度看,就不再是原来的那个对象了,而是使用一系列的装饰器装饰过后的对象。

2.结构

角色:

  • Component:组件对象的抽象接口,可以给这些对象动态的增加职责/功能。
  • ConcreteComponent:具体的组件的对象,实现组件对象的接口,是被装饰器装饰的原始对象,即可以给这个对象动态的添加职责。
  • Decorator:所有装饰器的抽象父类,实现了组件对象的接口,并且持有一个组件对象(被装饰的对象)。
  • ConcreteDecorator:具体的装饰器,具体实现向装饰对象添加功能。

普通示例

新建一个普通的蛋糕类:

public class Cake {

    public String getCakeMsg(){
        return "我是一个8英寸的普通蛋糕";
    }

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

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

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

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

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

import java.math.BigDecimal;

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

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

写个测试类测一下:

public class TestCake {
    public static void main(String[] args) {
        //普通蛋糕
        Cake cake = new Cake();
        System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());

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

        //加芒果和葡萄蛋糕
        CakeAddMangoAndGrape cakeAddMangoAndGrape = new CakeAddMangoAndGrape();
        System.out.println(cakeAddMangoAndGrape.getCakeMsg() + ",价格:" + cakeAddMangoAndGrape.getPrice());
    }
}

输出如下结果:

我是一个8英寸的普通蛋糕,价格:68
我是一个8英寸的普通蛋糕+1个芒果,价格:78
我是一个8英寸的普通蛋糕+1个芒果+1个葡萄,价格:83

看起来挺好的,能实现,但是假如我们加2个芒果呢?或者是我要加2个普通呢,或者说芒果和葡萄要组合,数量不一定,那利用现有的类是无法实现的,只能不断加类去重写,如果业务变更频繁,修改起来会是致命的。

正因为普通的实现方法有这种缺陷,才有了装饰者模式,接下来我们来看看同一个需求利用装饰者模式是怎么实现的吧。

装饰者模式示例

1、新建一个蛋糕的抽象类:

import java.math.BigDecimal;

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

    public abstract BigDecimal getPrice();
}

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

import java.math.BigDecimal;

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

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

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 CakeAddGrapeDecorator extends CakeDecorator {
    public CakeAddGrapeDecorator(Cake cake) {
        super(cake);
    }

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

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

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

 

public class CakeAddMangoDecorator extends CakeDecorator {

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

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

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

6、最后写一个测试类测试一下:

public class TestCakeDecorator {
    public static void main(String[] args) {
        Cake cake = null;
        //普通蛋糕
        cake = new BaseCake();
        System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());
        //加一个芒果
        cake = new CakeAddMangoDecorator(cake);
        System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());
        //加一个葡萄
        cake = new CakeAddGrapeDecorator(cake);
        System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());
        //再加一个芒果
        cake = new CakeAddMangoDecorator(cake);
        System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());
    }
}

输出结果为:

我是一个8英寸的普通蛋糕,价格:68
我是一个8英寸的普通蛋糕+1个芒果,价格:78
我是一个8英寸的普通蛋糕+1个芒果+1个葡萄,价格:83
我是一个8英寸的普通蛋糕+1个芒果+1个葡萄+1个芒果,价格:93

我们可以看到,使用装饰者模式之后,扩展之前的功能变得极为方便,可以根据现有的装饰器进行任意组合。

类图关系

看一下类图,首先是一个基础抽象类定义了基本方法,然后是基础实现和基础装饰器继承并重写抽象类中的方法:

装饰者模式使用场景

  • 1、用于扩展一个类的功能或给一个类添加附加职责。

  • 2、动态的给一个对象添加功能,这些功能可以再动态的撤销。

装饰者模式优点

  • 1、装饰者是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象 扩展功能,即插即用。

  • 2、通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。

  • 3、装饰者完全遵守开闭原则。

装饰者模式缺点

  • 1、会出现更多的代码,更多的类,增加程序复杂性。

  • 2、动态装饰以及多层装饰时会更加复杂。

标签:BigDecimal,getCakeMsg,模式,public,cake,getPrice,装饰
来源: https://www.cnblogs.com/sxw123/p/13825276.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有