当前位置: 首页 > news >正文

Java设计模式应用--装饰器模式

一、概念

装饰器模式概念:是指允许对一个现有的对象加入其它额外的功能并且不改变其原来的结构,属于结构型模式。这种模式通常会创建一个装饰类来包装原有的类以达到装饰的效果。

装饰器模式,顾名思义,就是对已经存在的某些类进行装饰,以此来扩展一些功能。

意图​:动态地给一个对象添加额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

二、应用

装饰器模式在实际项目中的应用:以我从事的支付行业为例。

核心角色​:

Component(抽象组件)​​:通常是接口或抽象类,定义了核心对象的行为。在支付系统中,这就是最核心的“支付”操作。

ConcreteComponent(具体组件)​​:实现了Component接口的核心对象,是我们要动态添加功能的对象。例如,一个基础的、只完成最基本支付流程的实现。

Decorator(抽象装饰器)​​:持有一个Component对象的引用,并实现Component接口。它是所有具体装饰器的父类。

ConcreteDecorator(具体装饰器)​​:向组件添加具体职责的类。

在支付系统中的常用应用场景

在支付中,支付流程是主流程,可以用装饰器模式给主流程进行扩展。

示例1:如一个简单的示例:日志记录,验证逻辑。当然在整个支付中,这样的应用很少,只是做个简单的引用。

简化代码:

// 1. 抽象组件 (Component)
public interface PaymentService {PayResult pay(PaymentRequest request);
}
// 2. 具体组件 (ConcreteComponent) - 基础支付实现
public class BasicPaymentService implements PaymentService {@Overridepublic PayResult pay(PaymentRequest request) {// 模拟调用支付网关的核心逻辑System.out.println("调用支付网关,扣款 " + request.getAmount() + " 元...");// ... 实际网络调用return new PayResult(200, "支付成功", "T123456");}
}
// 3. 抽象装饰器 (Decorator)
public abstract class PaymentDecorator implements PaymentService {protected PaymentService wrapped;public PaymentDecorator(PaymentService wrapped) {this.wrapped = wrapped;}@Overridepublic PayResult pay(PaymentRequest request) {return wrapped.pay(request);}
}
// 4. 具体装饰器 (ConcreteDecorator) - 日志记录
public class LoggingPaymentDecorator extends PaymentDecorator {public LoggingPaymentDecorator(PaymentService wrapped) {super(wrapped);}@Overridepublic PayResult pay(PaymentRequest request) {System.out.println("[INFO] 开始支付请求: " + request);try {PayResult result = super.pay(request);System.out.println("[INFO] 支付请求完成: " + result);return result;} catch (Exception e) {System.out.println("[ERROR] 支付请求异常: " + e.getMessage());throw e;}}
}
// 5. 具体装饰器 (ConcreteDecorator) - 参数验证
public class ValidationPaymentDecorator extends PaymentDecorator {public ValidationPaymentDecorator(PaymentService wrapped) {super(wrapped);}@Overridepublic PayResult pay(PaymentRequest request) {// 简单的验证逻辑if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {throw new IllegalArgumentException("支付金额必须大于0");}if (request.getToUserId() == null) {throw new IllegalArgumentException("收款方不能为空");}System.out.println("[VALID] 参数验证通过");return super.pay(request);}
}
// 测试类
public class PaymentDemo {public static void main(String[] args) {// 构建一个被“验证”和“日志”装饰的基础支付服务PaymentService paymentService = new BasicPaymentService();paymentService = new ValidationPaymentDecorator(paymentService);paymentService = new LoggingPaymentDecorator(paymentService);// 创建支付请求PaymentRequest request = new PaymentRequest(new BigDecimal("100.00"), "userA", "userB");// 执行支付PayResult result = paymentService.pay(request);}
}
输出结果:
[INFO] 开始支付请求: PaymentRequest(amount=100.00, fromUserId=userA, toUserId=userB)
[VALID] 参数验证通过
调用支付网关,扣款 100.00 元...
[INFO] 支付请求完成: PayResult(success=true, msg=支付成功, transactionId=T123456)

实际上在支付领域中,对于支付渠道路由/组合一般会采用装饰器和责任链设计模式。还有营销活动的叠加的技术选型中采用装饰器/策略模式。

示例2:如:电商系统中常见的优惠叠加装饰器

// 支付金额计算接口
public interface AmountCalculator {CalculationResult calculate(Order order);
}
// 基础计算器 - 原价计算
@Component
public class BaseAmountCalculator implements AmountCalculator {@Overridepublic CalculationResult calculate(Order order) {BigDecimal originalAmount = order.getTotalAmount();return new CalculationResult(originalAmount, originalAmount, "原价计算");}
}
// 优惠券装饰器
@Component
public class CouponCalculatorDecorator implements AmountCalculator {private final AmountCalculator wrapped;private final CouponService couponService;public CouponCalculatorDecorator(AmountCalculator wrapped, CouponService couponService) {this.wrapped = wrapped;this.couponService = couponService;}@Overridepublic CalculationResult calculate(Order order) {// 先计算基础金额CalculationResult baseResult = wrapped.calculate(order);// 应用优惠券Coupon coupon = couponService.getApplicableCoupon(order);if (coupon != null) {BigDecimal discountAmount = coupon.calculateDiscount(baseResult.getFinalAmount());BigDecimal finalAmount = baseResult.getFinalAmount().subtract(discountAmount);return new CalculationResult(baseResult.getOriginalAmount(),finalAmount,baseResult.getDescription() + ", 优惠券减免: " + discountAmount);}return baseResult;}
}
// 积分抵扣装饰器
@Component
public class PointsCalculatorDecorator implements AmountCalculator {private final AmountCalculator wrapped;private final PointsService pointsService;public PointsCalculatorDecorator(AmountCalculator wrapped, PointsService pointsService) {this.wrapped = wrapped;this.pointsService = pointsService;}@Overridepublic CalculationResult calculate(Order order) {CalculationResult baseResult = wrapped.calculate(order);// 计算可用积分抵扣int availablePoints = pointsService.getAvailablePoints(order.getUserId());BigDecimal pointsDiscount = pointsService.calculatePointsValue(availablePoints);if (pointsDiscount.compareTo(BigDecimal.ZERO) > 0) {BigDecimal finalAmount = baseResult.getFinalAmount().subtract(pointsDiscount);return new CalculationResult(baseResult.getOriginalAmount(),finalAmount.max(BigDecimal.ZERO), // 确保不低于0baseResult.getDescription() + ", 积分抵扣: " + pointsDiscount);}return baseResult;}
}
// 会员折扣装饰器
@Component
public class MemberDiscountCalculatorDecorator implements AmountCalculator {private final AmountCalculator wrapped;private final MemberService memberService;public MemberDiscountCalculatorDecorator(AmountCalculator wrapped, MemberService memberService) {this.wrapped = wrapped;this.memberService = memberService;}@Overridepublic CalculationResult calculate(Order order) {CalculationResult baseResult = wrapped.calculate(order);// 获取会员折扣BigDecimal discountRate = memberService.getMemberDiscount(order.getUserId());if (discountRate.compareTo(BigDecimal.ONE) < 0) {BigDecimal discountAmount = baseResult.getFinalAmount().multiply(BigDecimal.ONE.subtract(discountRate));BigDecimal finalAmount = baseResult.getFinalAmount().multiply(discountRate);return new CalculationResult(baseResult.getOriginalAmount(),finalAmount,baseResult.getDescription() + ", 会员折扣: " + discountRate + "折");}return baseResult;}
}
// 配置和使用
@Configuration
public class CalculatorConfig {@Beanpublic AmountCalculator compositeCalculator(CouponService couponService,PointsService pointsService,MemberService memberService) {// 构建计算链:原价 -> 会员折扣 -> 优惠券 -> 积分抵扣AmountCalculator calculator = new BaseAmountCalculator();calculator = new MemberDiscountCalculatorDecorator(calculator, memberService);calculator = new CouponCalculatorDecorator(calculator, couponService);calculator = new PointsCalculatorDecorator(calculator, pointsService);return calculator;}
}

配置类利用spring启动加载一次初始化完成时构建好了完整的装饰器链,并把calculator这个对象交给spring进行管理。

如果不好理解,可以使用另一种方式。

// 方法链方式(更易读)
public class CalculatorBuilder {private AmountCalculator calculator;public CalculatorBuilder base() {this.calculator = new BaseAmountCalculator();return this;}public CalculatorBuilder withMemberDiscount(MemberService service) {this.calculator = new MemberDiscountCalculatorDecorator(calculator, service);return this;}public CalculatorBuilder withCoupon(CouponService service) {this.calculator = new CouponCalculatorDecorator(calculator, service);return this;}public CalculatorBuilder withPoints(PointsService service) {this.calculator = new PointsCalculatorDecorator(calculator, service);return this;}public AmountCalculator build() {return calculator;}
}// 使用方式(更清晰)
AmountCalculator calculator = new CalculatorBuilder().base().withMemberDiscount(memberService).withCoupon(couponService).withPoints(pointsService).build();

// 业务使用
@Service
public class OrderService {private final AmountCalculator amountCalculator;public CreateOrderResult createOrder(CreateOrderRequest request) {Order order = buildOrder(request);// 自动应用所有优惠规则CalculationResult result = amountCalculator.calculate(order);order.setFinalAmount(result.getFinalAmount());order.setDiscountDescription(result.getDescription());return saveOrder(order);}
}

OrderService进行bean依赖注入,通过构造器注入。在OderService实例化时完成。

http://www.dtcms.com/a/548973.html

相关文章:

  • 【MATLAB例程】基于梯度检测自适应的互补滤波 vs 标准互补滤波,附MATLAB代码下载链接,可直接运行,方便学习和修改成自己想要的程序
  • 在检验铸铁平台精度使用三研法检验有哪些好处
  • 用Blender制作室内效果图宜居之地
  • blender4.5 使用外部IDE(pycharm)编辑脚本(bpy)实践指南
  • 计算机的一点基础知识
  • 广州网站建设 乐云seo国外优秀论文网站
  • CSS 图像拼合技术
  • 【C++】模板进阶 | 继承
  • 排名优化网站建设长沙网站建设优化
  • 厦门网站优化服务pyhton做网站
  • 论文阅读笔记——数据增强
  • 如何裁剪YOLOv8m的大目标检测头并验证其结构
  • 扩展阅读:目标检测(Object Detection)标注
  • MR30分布式IO:破局锂电池制造产线,引领高效生产新变革
  • AI赋能科研创新:ChatGPT-4o与DeepSeek-R1在学术研究中的深度应用指南
  • 《数据库系统》SQL语言之分组查询与分组过滤(理论理解分析+实例练习)
  • 家乡介绍网页设计海口seo网络推广
  • 【ROS2】动作服务器:rclcpp_action::Client 详解
  • 红松APP首秀北京老博会,“有温度的科技”赋能退休兴趣生活
  • 【ZEGO即构开发者日报】Soul AI Lab开源播客语音合成模型;腾讯混元推出国内首个交互式AI播客;ChatGPT Go向用户免费开放一年......
  • 数据库基础-数据库的三级模式
  • 图书馆网站建设调查问卷wordpress小工具自定义
  • 前端兼容性与调试技巧完全指南
  • 深度解析 Rust 的数据结构:标准库与社区生态
  • 关于组态软件的三个误解
  • 需要使用耐高温过炉治具的产品类型
  • qt QPushButton 启用选中状态(按钮可切换状态)
  • 河北云网站建设免费空间做网站
  • webrtc代码走读(十二)Transport-cc协议与RTP扩展头
  • 前端多版本零404部署实践:为什么会404,以及怎么彻底解决