目录
一、基本概念
二、UML类图
三、角色设计
四、代码实现
案例一
案例二
五、总结
装饰器模式是指不必在改变原有的类和不使用继承的情况下,动态扩展一个对象的功能。
角色 | 描述 |
---|---|
抽象构件 | 是一个接口或者抽象类,定义我们最核心的对象 |
具体构件 | 抽象构件的实现,可以单独用,也可以将其进行装饰 |
装饰角色 | 一般是一个抽象类,继承自或实现抽象构件,在它的属性中有个变量指向抽象构建,这是关键 |
具体装饰角色 | 具体的装饰类,可以把基础构件进行装饰,延伸出新的功能 |
假设一个场景,以前手机充电只有usb充电,但是目前手机多出了2种新的充电方式,Typc-C和无线充电,这就需要我们动态去扩展功能,让我们看看装饰器如何实现的。
首先定义一个基本的充电接口,采用usb充电:
public interface Charge {
public void usb();
}
实现一个普通手机去使用usb接口充电:
public class PhoneCharge implements Charge{
@Override
public void usb() {
System.out.println("采用usb接口充电...");
}
}
抽象的充电装饰器:
public abstract class AbstractPhoneDecorator implements Charge{
protected final Charge charge;
public AbstractPhoneDecorator(Charge charge){
this.charge = charge;
}
}
Type-C充电具体装饰:
public class TypeCDecorator extends AbstractPhoneDecorator{
public TypeCDecorator(Charge charge) {
super(charge);
}
@Override
public void usb() {
super.charge.usb();
System.out.println("采用type-c接口充电...");
}
}
无线充电的具体装饰:
public class WirelessDecorator extends AbstractPhoneDecorator{
public WirelessDecorator(Charge charge) {
super(charge);
}
@Override
public void usb() {
super.charge.usb();
System.out.println("采用无线充电...");
}
}
客户端:
public class Client {
public static void main(String[] args) {
Charge charge = new PhoneCharge();
TypeCDecorator typeCDecorator = new TypeCDecorator(charge);
WirelessDecorator wirelessDecorator = new WirelessDecorator(typeCDecorator);
wirelessDecorator.usb();
}
}
运行结果如下:
现在假设有一个新的场景,在我们平时网上购买一个商品可以不光使用红包抵扣,同时也有满减优惠,案例二假设一个用户在网上买了10个单价为15元的牙杯,他现在有一个20元的红包和50元的抵扣券,下面通过代码来进行简单的模拟实现。
创建订单实体类:
import java.math.BigDecimal;
/**
* 订单类
* @author HTT
*/
public class Order {
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getGoodsInfo() {
return goodsInfo;
}
public void setGoodsInfo(String goodsInfo) {
this.goodsInfo = goodsInfo;
}
public BigDecimal getGoodsPrice() {
return goodsPrice;
}
public void setGoodsPrice(BigDecimal goodsPrice) {
this.goodsPrice = goodsPrice;
}
public BigDecimal getGoodsCount() {
return goodsCount;
}
public void setGoodsCount(BigDecimal goodsCount) {
this.goodsCount = goodsCount;
}
public Coupon getFullReduction() {
return fullReduction;
}
public void setFullReduction(Coupon couponInfo) {
this.fullReduction = couponInfo;
}
public Coupon getRedPacketInfo() {
return redPacketInfo;
}
public void setRedPacketInfo(Coupon redPacketInfo) {
this.redPacketInfo = redPacketInfo;
}
public BigDecimal getGoodsAmount() {
return goodsAmount;
}
public void setGoodsAmount(BigDecimal goodsAmount) {
this.goodsAmount = goodsAmount;
}
/**
* 订单id
*/
private String id;
/**
* 商品信息
*/
private String goodsInfo;
/**
* 商品价格
*/
private BigDecimal goodsPrice;
/**
* 商品信息
*/
private BigDecimal goodsCount;
/**
* 商品总价
*/
private BigDecimal goodsAmount;
/**
* 满减信息
*/
private Coupon fullReduction;
/**
* 红包信息
*/
private Coupon redPacketInfo;
}
创建优惠券实体类:
import java.math.BigDecimal;
/**
* 优惠信息
* @author HTT
*/
public class Coupon {
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public BigDecimal getCouponPrice() {
return couponPrice;
}
public void setCouponPrice(BigDecimal couponPrice) {
this.couponPrice = couponPrice;
}
public String getCouponType() {
return couponType;
}
public void setCouponType(String couponType) {
this.couponType = couponType;
}
private int id;
/**
* 优惠金额
*/
private BigDecimal couponPrice;
/**
* 优惠券类型
*/
private String couponType;
}
创建一个抽象构建,是所有订单的基本需求,用于计算订单的总额:
/**
* 抽象构建 用于计算订单总金额
* @author HTT
*/
public interface OrderDecorator {
public BigDecimal calculateOrderPrice(Order order);
}
抽象构建的基础实现类:
/**
* 基础构建实现类 计算订单金额
* @author HTT
*/
public class BaseOrder implements OrderDecorator{
@Override
public BigDecimal calculateOrderPrice(Order order) {
return order.getGoodsPrice().multiply(order.getGoodsCount());
}
}
订单的抽象装饰器:
/**
* 抽象的订单装饰器
* @author HTT
*/
public abstract class BaseOrderDecorator implements OrderDecorator{
private OrderDecorator orderDecorator;
public BaseOrderDecorator(OrderDecorator orderDecorator){
this.orderDecorator = orderDecorator;
}
@Override
public BigDecimal calculateOrderPrice(Order order) {
return orderDecorator.calculateOrderPrice(order);
}
}
红包装饰器:
/**
* 红包装饰器
* @author HTT
*/
public class RedPacketDecorator extends BaseOrderDecorator{
public RedPacketDecorator(OrderDecorator orderDecorator) {
super(orderDecorator);
}
@Override
public BigDecimal calculateOrderPrice(Order order) {
order.setGoodsAmount(super.calculateOrderPrice(order));
return calculateRedPacketPrice(order);
}
private BigDecimal calculateRedPacketPrice(Order order){
return order.getGoodsAmount().subtract(order.getRedPacketInfo().getCouponPrice());
}
}
满减装饰器:
/**
* 满减装饰器
* @author HTT
*/
public class FullReductionDecorator extends BaseOrderDecorator{
public FullReductionDecorator(OrderDecorator orderDecorator) {
super(orderDecorator);
}
@Override
public BigDecimal calculateOrderPrice(Order order) {
order.setGoodsAmount(super.calculateOrderPrice(order));
return calculateRedPacketPrice(order);
}
private BigDecimal calculateRedPacketPrice(Order order){
return order.getGoodsAmount().subtract(order.getFullReduction().getCouponPrice());
}
}
客户端:
public class Client {
public static void main(String[] args) {
//初始化红包信息
Coupon redPacket = new Coupon();
redPacket.setId(1);
redPacket.setCouponType("红包");
redPacket.setCouponPrice(new BigDecimal("20"));
//初始化满减信息
Coupon fullReduction = new Coupon();
fullReduction.setId(2);
fullReduction.setCouponType("满减");
fullReduction.setCouponPrice(new BigDecimal("50"));
//初始化订单信息
Order order = new Order();
order.setId(UUID.randomUUID().toString());
order.setGoodsInfo("牙杯");
order.setGoodsPrice(new BigDecimal("15"));
order.setGoodsCount(new BigDecimal("10"));
order.setRedPacketInfo(redPacket);
order.setFullReduction(fullReduction);
OrderDecorator orderDecorator = new BaseOrder();
BaseOrderDecorator redPacketDecorator = new RedPacketDecorator(orderDecorator);
BaseOrderDecorator fullReductionDecorator = new FullReductionDecorator(redPacketDecorator);
System.out.println(fullReductionDecorator.calculateOrderPrice(order));
}
}
运行结果如下:
优点:
1、扩展开闭原则。可以通过装饰类扩展功能,而无需修改原类。
2、装饰类和原类接口一致。对使用者透明,易于使用。
3、具体构件类和装饰类可以独立变化,用户可根据需要增加装饰类链。
4、使用组合方式代替继承,更加灵活。
缺点:
1、装饰链过多时,调试和阅读代码困难。
2、不符合单一职责原则,容易出现多装饰器堆叠的情况。
应用场景:
1、扩展类功能场景,特别不希望通过子类继承的方式扩展。
2、动态给对象增加功能,且可按需挑选需要的功能。
3、需要通过对多个类的组合展现功能,而非继承。装饰器模式利用封装和组合的方式灵活地扩展对象功能,遵循开闭原则,而不破坏继承关系。适用于功能扩展的场景中。
符合的设计原则:
1、单一职责原则(Single Responsibility Principle)
装饰类只负责为对象新增功能,而不修改其本身功能。
2、开闭原则(Open Closed Principle)
可以新增装饰类而不需要修改源代码,扩展开放。
3、里氏替换原则(Liskov Substitution Principle)
装饰对象可以替换被装饰对象使用,不影响其他对象。
4、依赖倒转原则(Dependency Inversion Principle)
装饰类和被装饰类都依赖于抽象组件接口,不存在具体依赖。
5、接口隔离原则(Interface Segregation Principle)
组件接口职责单一,不需要强制实现不必要的方法。
装饰器模式通过对象组合方式动态增强功能,遵循开闭原则,在不修改源代码的前提下扩展对象功能,是继承的一个有力补充。