目 录CONTENT

文章目录

装饰者模式

小王同学
2023-12-24 / 0 评论 / 0 点赞 / 44 阅读 / 0 字

装饰者模式

微信公众号:新时代程序猿
关注可了解更多的JAVA,PYTHON,ANDROID教程及开发技术。
问题或建议,请公众号留言;
如果你觉得文章对你有帮助,欢迎赞赏

什么是装饰者模式

装饰者模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰者来包裹真实的对象。

所以装饰者可以动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的方案。

装饰者模式组成结构

  • Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
  • ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
  • Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
  • ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。

装饰者模式 UML 图解

装饰者模式应用场景

  • 需要扩展一个类的功能,或给一个类添加附加职责。
  • 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  • 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
  • 当不能采用生成子类的方法进行扩充时。可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。

装饰者模式特点

  • 装饰者对象和具体构件有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
  • 装饰者对象包含一个具体构件的引用(reference)。
  • 装饰者对象接受所有来自客户端的请求。它把这些请求转发给具体构件。
  • 装饰者对象可以在转发这些请求以前或以后动态增加一些功能。

说了这么多,我们还是要实践代码才行啊,毕竟实践才是检验真理的唯一标准!!
将装饰者模式应用到问题中去:
大家都喝过奶茶吧,别说你没喝过,没喝过的都单身哈哈哈,先说奶茶有很多种口味,比如说珍珠奶茶,巧克力奶茶,丝袜奶茶,可以加佐料,比如冰块,柠檬,椰果等等,假如我们想要加冰和柠檬的珍珠奶茶,那么,要做的是:

拿一个珍珠奶茶 (PearlMilkTea) 对象
以冰块 (IceBlock) 装饰它
以柠檬 (Lemon) 装饰它
调用 cost() 方法,并依赖委托将调料的价钱加上去

首先创建一个抽象构件,我们的奶茶抽象类

/**
 * 奶茶
 */
public abstract class MilkTea {
    public abstract String getDescription();
    public abstract double cost();
}

接着创建三个具体构件:珍珠奶茶,巧克力奶茶,丝袜奶茶

巧克力奶茶

/**
 * 巧克力奶茶
 */
public class ChocolateMilkTea extends MilkTea {

    @Override
    public String getDescription() {
        return "巧克力奶茶";
    }

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

珍珠奶茶

/**
 * 珍珠奶茶
 */
public class PearlMilkTea extends MilkTea{


    @Override
    public String getDescription() {
        return "珍珠奶茶";
    }

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

丝袜奶茶

/**
 * 丝袜奶茶
 */
public class HongKongStyleMilkTea extends MilkTea{

    @Override
    public String getDescription() {
        return "丝袜奶茶";
    }

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

抽象装饰类,需要注意的是,抽象装饰类通过成员属性的方式将 奶茶抽象类组合进来,同时也继承了奶茶抽象类,且这里定义了新的业务方法 doSomething()

public abstract class CondimentDecorator extends MilkTea{
    MilkTea milkTea;

    public CondimentDecorator(MilkTea milkTea) {
        this.milkTea = milkTea;
    }

    protected abstract void doSomething();

    @Override
    public String getDescription() {
        return this.milkTea.getDescription();
    }

    @Override
    public double cost() {
        return this.milkTea.cost();
    }
}

具体抽象类:冰块装饰器,继承了抽象装饰类,冰块装饰器在父类的基础上增加了冰块,同时价格加上 1 块钱

public class IceBlockDecorator extends CondimentDecorator {

    public IceBlockDecorator(MilkTea milkTea) {
        super(milkTea);
    }

    @Override
    public String getDescription() {
        return super.getDescription()+"加冰块";
    }

    @Override
    public double cost() {
        return super.cost() + 1.0;
    }

    public void addIceBlock(){
        System.out.println("加冰块");
    }

    @Override
    protected void doSomething() {

    }
}

具体抽象类:柠檬装饰器,继承了抽象装饰类,柠檬装饰器在父类的基础上增加了柠檬,同时价格加上 5 块钱

public class LemonDecorator extends CondimentDecorator{
    public LemonDecorator(MilkTea milkTea) {
        super(milkTea);
    }
    @Override
    public String getDescription() {
        return super.getDescription()+"加柠檬";
    }

    @Override
    public double cost() {
        return super.cost()+5.0;
    }

    @Override
    protected void doSomething() {

    }
}

测试,最后我们在main方法创建一杯珍珠奶茶+冰块+柠檬

public class Client {
    public static void main(String[] args) {
        MilkTea pearlMilkTea = new PearlMilkTea();
        pearlMilkTea = new IceBlockDecorator(pearlMilkTea);
        pearlMilkTea = new LemonDecorator(pearlMilkTea);
        System.out.println(pearlMilkTea.getDescription()+": $:"+pearlMilkTea.cost());
    }
}

输出:

珍珠奶茶加冰块加柠檬: $:25.9

创建一杯丝袜奶茶+冰块+柠檬+柠檬,我们这次加了两次柠檬,看看是什么效果吧~

public class Client {
    public static void main(String[] args) {
  
        MilkTea hongKongStyleMilkTea = new HongKongStyleMilkTea();
        hongKongStyleMilkTea = new IceBlockDecorator(hongKongStyleMilkTea);
        hongKongStyleMilkTea = new LemonDecorator(hongKongStyleMilkTea);
        hongKongStyleMilkTea = new LemonDecorator(hongKongStyleMilkTea);
        System.out.println(hongKongStyleMilkTea.getDescription()+": $:"+hongKongStyleMilkTea.cost());
    
    }
}

输出:

丝袜奶茶加冰块加柠檬加柠檬: $:50.9

装饰者模式总结

装饰模式的主要优点如下:

对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。
可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为。
可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,得到功能更为强大的对象。
具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无须改变,符合 “开闭原则”。

装饰模式的主要缺点如下:

使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,大量小对象的产生势必会占用更多的系统资源,在一定程序上影响程序的性能。
装饰模式提供了一种比继承更加灵活机动的解决方案,但同时也意味着比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐。

送大家一份福利:关注本公众号并回复“code”,即可获得大厂面试总结、python、java各种电子书,满满的干货!!

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区