一文搞懂Java的装饰器设计模式

装饰器设计模式

微信搜索关注《Java学研大本营》,加入读者群,分享更多精彩

我们有一个名为Payment的接口,其中包含一个支付方法。

一个具体的DefaultPayment类来实现该方法,该方法将price作为参数来执行支付逻辑。

public  interface  Payment { 
    void  pay (BigDecimal price) ; 
}
public  class  DefaultPayment  implements  Payment { 
    @Override 
    public  void  pay (BigDecimal price) { 
        System.out.println( "Payed: " + price); } 
    } 
}

客户可以使用DefaultPayment支付:

public  class  Client { 
    public  static  void  main (String[] args) { 
        Payment  defaultPayment  =  new  DefaultPayment (); 
        defaultPayment.pay(BigDecimal.valueOf( 100 )); 
    } 
}

介绍装饰者模式

假设我想支付的产品有税,我该怎么办?我们可以利用我们的设计,我们是为接口而不是为实现而设计的。

因此,我们可以为Payment创建一个类,让它成为一种Payment类型,同时将Payment保存为属性,它可以使用其构造函数获取付款,我们将调用此类TaxPaymentDecorator

public class TaxPaymentDecorator implements Payment {
    private Payment payment;
    private BigDecimal tax = BigDecimal.ZERO;

    public TaxPaymentDecorator(Payment payment) {
        this.payment = payment;
    }

    @Override
    public void pay(BigDecimal price) {
        price = price.add(this.tax);
        payment.pay(price);
    }

    public BigDecimal getTax() {
        return tax;
    }

    public void setTax(BigDecimal tax) {
        this.tax = tax;
    }
}

如您所见,这个装饰器可以在注入 throw 装饰器构造函数的 Payment 的pay方法之前添加税。

客户可以按如下方式使用TaxPaymentDecorator

public class Client {
    public static void main(String[] args) {
        TaxPaymentDecorator taxPaymentDecorator = new TaxPaymentDecorator(new DefaultPayment());
        taxPaymentDecorator.setTax(BigDecimal.valueOf(50));
        taxPaymentDecorator.pay(BigDecimal.valueOf(100));
    }
}

想象一下这个产品有折扣,使用我们可以为 Payment 使用装饰器的相同概念。

public class DiscountPaymentDecorator implements Payment {
    private Payment payment;
    private BigDecimal discount = BigDecimal.ZERO;

    public DiscountPaymentDecorator(Payment payment) {
        this.payment = payment;
    }

    @Override
    public void pay(BigDecimal price) {
        price = price.subtract(discount);
        payment.pay(price);
    }

    public BigDecimal getDiscount() {
        return discount;
    }

    public void setDiscount(BigDecimal discount) {
        this.discount = discount;
    }
}

我们可以使用DiscountPaymentDecorator从有或没有 TaxPaymentDecorator 的价格中减去它,客户可以使用它们:

public class Client {
    public static void main(String[] args) {
        TaxPaymentDecorator taxPaymentDecorator = new TaxPaymentDecorator(new DefaultPayment());
        taxPaymentDecorator.setTax(BigDecimal.valueOf(50));
        DiscountPaymentDecorator discountPaymentDecorator = new DiscountPaymentDecorator(taxPaymentDecorator);
        discountPaymentDecorator.setDiscount(BigDecimal.valueOf(10));
        discountPaymentDecorator.pay(BigDecimal.valueOf(100));
    }
}

并且以同样的方式,装饰器可以在方法之后添加自己。

UML图

装饰器设计模式UML图

设计原则

我将在这里讨论三个设计原则:

  • 为接口而不是为实现而设计:如您所见,使用Payment接口帮助我们通过在运行时动态添加行为来使用 OOP 的强大功能,而无需对旧实现进行任何修改。

  • 设计对扩展开放,关闭修改:这一点与前一点有关,我们的旧实现没有强制我们做任何修改,但我们扩展了旧实现以添加新行为,我的意思是这里使用接口代替的设计实施。

  • 更倾向组合而不是继承:装饰器在这里使用组合而不是尝试使用继承,通常使用继承会增加耦合而导致问题,我们可以在单独的博客中讨论。

书籍定义

动态地将附加职责附加到对象。装饰器为扩展功能提供了一种灵活的子类化替代方案。

在我们的示例中,我们在运行时动态附加了两个职责,我们对价格加税并从价格中减去折扣,我们没有对 DefaultPayment 进行子类化,我们使用 OOP 的强大功能以灵活的方式添加我们的行为,这就是装饰者模式。

推荐书单

《项目驱动零起点学Java》

《项目驱动零起点学Java》共分 13 章,围绕 6 个项目和 258 个代码示例,分别介绍了走进Java 的世界、变量与数据类型、运算符、流程控制、方法、数组、面向对象、异常、常用类、集合、I/O流、多线程、网络编程相关内容。《项目驱动零起点学Java》总结了马士兵老师从事Java培训十余年来经受了市场检验的教研成果,通过6 个项目以及每章的示例和习题,可以帮助读者快速掌握Java 编程的语法以及算法实现。扫描每章提供的二维码可观看相应章节内容的视频讲解。

《项目驱动零起点学Java》贯穿6个完整项目,经过作者多年教学经验提炼而得,项目从小到大、从短到长,可以让读者在练习项目的过程中,快速掌握一系列知识点。

马士兵,马士兵教育创始人,毕业于清华大学,著名IT讲师,所讲课程广受欢迎,学生遍布全球大厂,擅长用简单的语言讲授复杂的问题,擅长项目驱动知识的综合学习。马士兵教育获得在线教育“名课堂”奖、“最受欢迎机构”奖。

赵珊珊,从事多年一线开发,曾为国税、地税税务系统工作。拥有7年一线教学经验,多年线上、线下教育的积累沉淀,培养学员数万名,讲解细致,脉络清晰。

《项目驱动零起点学Java》(马士兵,赵珊珊)【摘要 书评 试读】- 京东图书京东JD.COM图书频道为您提供《项目驱动零起点学Java》在线选购,本书作者:,出版社:清华大学出版社。买图书,到京东。网购图书,享受最低优惠折扣!icon-default.png?t=N5K3https://item.jd.com/13607758.html

精彩回顾

数据架构演进史(上)

数据架构演进史(下)

如何选择适合的后端框架

微信搜索关注《Java学研大本营》

访问【IT今日热榜】,发现每日技术热点

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值