装饰器设计模式
微信搜索关注《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学研大本营》
访问【IT今日热榜】,发现每日技术热点