Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

Chain With Ordered Links

This project presents how to use COR Bean Processor Spring Boot Starter to create a chain with links in a specific order.

The logic objective in this project is to calculate order discounts. Each order is composed of items, their amounts and the type of customer that wants to buy it. There are three different types of discounts that the program can provide: Bundle, quantity and customer type.

Bundle discounts are given when customers buy a specific group of different items. The discount reduces a percentage on the bundle pack price.

Bundle Discount Name Items And Quantity Discount Percentage
Quick Snack Pack 1 sandwich, 1 juice box, 1 chocolate bar 18%
Family Meal 3 sandwiches, 3 juice boxes 22%
Refresh Flash 2 juice box, 2 chocolate bars 8%

Quantity discounts are given when customers buy a certain amount of the same item. The discount reduces a percentage on the item quantity price.

Quantity Discount Name Items And Quantity Discount Percentage
Refreshing dozen 12 juice boxes 10%
3+1 sandwiches 4 sandwiches 25%
Delicious trio 3 chocolate bars 5%

Customer type discounts are given for different customer types. Usual customers do not receive any discount, while frequent customers are given a 3% discount on all items.

Bundle and quantity discounts are non-stackable and bundle discounts have a higher priority. This means that if an order already has bundled discounts, it cannot receive quantity discounts. On the opposite, if the order does not have any bundle discount, then quantity discounts are checked. Customer discounts are always given regardless if the order already has other discounts applied.

The discounts are given based on a chain of responsibility model.

An Unified Modeling (UML) Diagram presenting the structure developed to check discounts on each order.

But since we have discount types with different priorities, we need to order the chain as follows:

  1. Bundled discounts
  2. Quantity discounts
  3. Customer type discounts

Highlights

DiscountCheckerLink interface extends COR Bean Processor Spring Boot Starter ChainLink<T> interface passing a self-reference as parameter. It also contains the entry method used to check and apply a discount type for an order.

public interface DiscountCheckerLink extends ChainLink<DiscountCheckerLink> {

  Order check(Order order);
}

AbstractDiscountCheckerLink is an abstract class that implements DiscountCheckerLink interface. It also implements check method demanded by DiscountCheckerLink and setNext method demanded by ChainLink. The latter is implemented using Lombok @Setter annotation.

Since discount types depends on certain rules to be applied, the class declares an abstract method isCandidate, demanding its specializations to implement a method to check if analysed order is a valid candidate for discounts.

To separate the chain execution from the actual discount application, the class also declares an abstract method doCheck, which will be executed if the order is a candidate for the discount type checking. Inside it, the class specializations will elaborate the logic to apply the discounts.

public abstract class AbstractDiscountCheckerLink implements DiscountCheckerLink {

  @Setter
  private DiscountCheckerLink next;

  @Override
  public Order check(Order order) { /* Full logic can be checked on the class implementation. */ }

  protected abstract Order doCheck(Order order);

  protected abstract boolean isCandidate(Order order);
}

BundleDiscountCheckerLink, QuantityDiscountCheckerLink and CustomerTypeDiscountCheckerLink classes extend AbstractDiscountCheckerLink abstract class and implement the logic to apply the discounts. They are also decorated with Spring @Order annotation to specify the link order in the chain.

@Order(10)
public class BundleDiscountCheckerLink extends AbstractDiscountCheckerLink {

  @Override
  protected Order doCheck(Order order) { /* Full logic can be checked in the class implementation. */ }

  @Override
  protected boolean isCandidate(Order order) { /* Full logic can be checked in the class implementation. */ }
}
@Order(20)
public class QuantityDiscountCheckerLink extends AbstractDiscountCheckerLink {

  @Override
  protected Order doCheck(Order order) { /* Full logic can be checked in the class implementation. */ }

  @Override
  protected boolean isCandidate(Order order) { /* Full logic can be checked in the class implementation. */ }
}
@Order(30)
public class CustomerTypeDiscountCheckerLink extends AbstractDiscountCheckerLink {

  @Override
  protected Order doCheck(Order order) { /* Full logic can be checked in the class implementation. */ }

  @Override
  protected boolean isCandidate(Order order) { /* Full logic can be checked in the class implementation. */ }
}

DiscountService encapsulates the components required to check and calculate order discounts. It contains a calculateDiscounts method which invokes the first link check method, starting the chain analysis.

public class DiscountService {

  private final DiscountCheckerLink firstLink;

  public Order calculateDiscounts(Order order) {
    return firstLink.check(order);
  }
}

Execution

The complete integration with Spring Boot can be checked on DiscountServiceIT. It is an integration test class and can be executed through an IDE like IntelliJ IDEA, Eclipse or Microsoft Visual Studio Code.

Alternatively, the tests can also be executed through a terminal running the following command on this module root directory.

mvn test-compile failsafe:integration-test