Practice of decorator design pattern in business

Posted by a.heresey on Wed, 19 Jan 2022 10:07:29 +0100

Practice of decorator design pattern in business

Decorator design pattern, as its name implies, is a layer of decorative logic on the original logic, so as to realize the elegant expansion of basic logic without if else. The decorator's design pattern is used in the InputStream in the JDK source code. So as to modify InputStream through BufferedInputStream, DataInputStream and other functions, and add cache reading, type reading and other functions, which is equivalent to adding many modification functions on InputStream, so it is a decorator mode.

Here, inputStream is used as a decorated class, and then BufferedInputStream adds decoration with buffer function to the function

It can also be seen from the constructor.

When initializing the constructor, an inputStream needs to be passed in

Simply construct a scene that can use decorator mode.

Now you need to calculate the actual payment amount of an order.

1: Calculate the original price of the commodity.

2: There are coupons, and the original price of the commodity needs to be deducted.

3: If there is a red envelope, you also need to deduct the empty envelope amount.

This scenario can be realized by writing a long piece of code through if else, but it doesn't feel elegant and extensible. If else scenarios can be handled through strategy mode, responsibility chain mode and decorator mode.

However, there may be a variety of preferential strategies, which are not suitable for the strategy mode. The responsibility chain mode is also possible. Here we focus on the decorator mode. There is no discussion here.

Combing: Here we can define a base class for calculating the price. We can use the decorator mode to decorate the original class. So as to realize the superposition calculation of multiple preferences.

Pseudo code

Define an order object. An order contains multiple sub orders. Each sub order contains a commodity, commodity binding price, and multiple preferential information.

Here we mainly focus on discount information and define two types of discounts: 1: discount and 2: red envelope

Each preference type describes the amount of preference through attributes

public class Order {
  
  private int id; //Order ID
  private String orderNo; //order number
  private BigDecimal totalPayMoney; //Total payment amount
  private List<OrderDetail> list; //Detailed order list
}

public class OrderDetail {
  private int id; //Detailed order ID
  private int orderId;//Master order ID
  private Merchandise merchandise; //Product details
  private BigDecimal payMoney; //Pay unit price
}

public class Merchandise {
  
  private String sku;//Product SKU
  private String name; //Trade name
  private BigDecimal price; //item pricing 
  private Map<String, SupportPromotions> supportPromotions; //Support promotion type
}

public class UserCoupon {
  
  private int id; //Coupon ID
  private int userId; //Coupon user ID
  private String sku; //Product SKU
  private BigDecimal coupon; //Preferential amount
}

public class UserRedPacket {

  private int id; //Red envelope ID
  private int userId; //Get user ID
  private String sku; //Product SKU
  private BigDecimal redPacket; //Receive red envelope amount
}

Then define an interface to calculate the order amount

public interface IBaseCount {
  
  BigDecimal countPayMoney(OrderDetail orderDetail);

}

Build the abstract class to calculate the order amount, no discount calculation class and red envelope discount calculation class respectively

public abstract class BaseCountDecorator implements IBaseCount{
  
  private IBaseCount count;
  
  public BaseCountDecorator(IBaseCount count) {
    this.count = count;
  }

  public BigDecimal countPayMoney(OrderDetail orderDetail) {
    BigDecimal payTotalMoney = new BigDecimal(0);
    if(count!=null) {
      payTotalMoney = count.countPayMoney(orderDetail);
    }
    return payTotalMoney;
  }
}
public class CouponDecorator extends BaseCountDecorator{

  public CouponDecorator(IBaseCount count) {
    super(count);
  }
  
  public BigDecimal countPayMoney(OrderDetail orderDetail) {
    BigDecimal payTotalMoney = new BigDecimal(0);
    payTotalMoney = super.countPayMoney(orderDetail);
    payTotalMoney = countCouponPayMoney(orderDetail);
    return payTotalMoney;
  }
  
  private BigDecimal countCouponPayMoney(OrderDetail orderDetail) {
    
    BigDecimal coupon =  orderDetail.getMerchandise().getSupportPromotions().get(PromotionType.COUPON).getUserCoupon().getCoupon();
    System.out.println("Coupon amount:" + coupon);
    
    orderDetail.setPayMoney(orderDetail.getPayMoney().subtract(coupon));
    return orderDetail.getPayMoney();
  }
}
public class RedPacketDecorator extends BaseCountDecorator{

  public RedPacketDecorator(IBaseCount count) {
    super(count);
  }
  
  public BigDecimal countPayMoney(OrderDetail orderDetail) {
    BigDecimal payTotalMoney = new BigDecimal(0);
    payTotalMoney = super.countPayMoney(orderDetail);
    payTotalMoney = countCouponPayMoney(orderDetail);
    return payTotalMoney;
  }
  
  private BigDecimal countCouponPayMoney(OrderDetail orderDetail) {
    
    BigDecimal redPacket = orderDetail.getMerchandise().getSupportPromotions().get(PromotionType.REDPACKED).getUserRedPacket().getRedPacket();
    System.out.println("Red envelope discount amount:" + redPacket);
    
    orderDetail.setPayMoney(orderDetail.getPayMoney().subtract(redPacket));
    return orderDetail.getPayMoney();
  }
}
public class BaseCount implements IBaseCount{

  public BigDecimal countPayMoney(OrderDetail orderDetail) {
orderDetail.setPayMoney(orderDetail.getMerchandise().getPrice());
    System.out.println("The original unit price of goods is:" +  orderDetail.getPayMoney());
    
    return orderDetail.getPayMoney();
  }

}

The whole system for calculating the amount of money has been established.

These calculations are then connected through a calculation factory class

public class PromotionFactory {
  
  public static BigDecimal getPayMoney(OrderDetail orderDetail) {
    
    //Get the promotion type set for the product
    Map<String, SupportPromotions> supportPromotionslist = orderDetail.getMerchandise().getSupportPromotions();
    
    //Initialize calculation class
    IBaseCount baseCount = new BaseCount();
    if(supportPromotionslist!=null && supportPromotionslist.size()>0) {
      for(String promotionType: supportPromotionslist.keySet()) {//Traverse the set promotion types and combine promotion types through decorators
        baseCount = protmotion(supportPromotionslist.get(promotionType), baseCount);
      }
    }
    return baseCount.countPayMoney(orderDetail);
  }
  
  /**
   * Combined promotion type
   * @param supportPromotions
   * @param baseCount
   * @return
   */
  private static IBaseCount protmotion(SupportPromotions supportPromotions, IBaseCount baseCount) {
    if(PromotionType.COUPON.equals(supportPromotions.getPromotionType())) {
      baseCount = new CouponDecorator(baseCount);
    }else if(PromotionType.REDPACKED.equals(supportPromotions.getPromotionType())) {
      baseCount = new RedPacketDecorator(baseCount);
    }
    return baseCount;
  }

}

Obtain all promotion types on the sub order goods through the getPayMoney method of the factory class, then obtain the final decoration object in turn, calculate the order amount, and finally obtain the final amount.

DEMO

 public static void main( String[] args ) throws InterruptedException, IOException
    {
        Order order = new Order();
        init(order);

        for(OrderDetail orderDetail: order.getList()) {
            BigDecimal payMoney = PromotionFactory.getPayMoney(orderDetail);
            orderDetail.setPayMoney(payMoney);
            System.out.println("Final payment amount:" + orderDetail.getPayMoney());
        }
    }

Get execution results:

The original unit price of the commodity is 100
 Red envelope discount amount: 10
 Coupon amount: 10
 Final payment amount: 80

In fact, this method is very similar to the design pattern of mybatis plug-in (chain of responsibility + dynamic agent)

 

Turn https://www.cnblogs.com/simple-flw/p/15811736.html

Topics: Design Pattern