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