Order and combination mode

order

Orders are very common in our daily life. Sometimes an order contains other orders, as follows:

The order contains two sub orders and a bottle of milk, and the two sub orders have their own contents. In this way, an order tree is formed. The specific goods are leaf nodes and orders are non leaf nodes. As follows:

So what should we do with this tree structure? The answer is to use combination mode

Combination mode

Composite mode is a structural design mode. You can use it to combine objects into a tree structure, and you can use them like independent objects. Therefore, composite mode is also called "partial overall mode".

code

Next, let's use the code to feel the combination mode.

Define top-level interfaces

First, we define the top-level interface. I call it "calculatable", which means something that can be valued. In the later code, anything can be valued.

/**
 * @author skyline
 */
public interface CalculateAble {
    /**
     * Calculate price
     */
    double calculate();

    /**
     * Current trade name
     * @return
     */
    String name();

    /**
     * Add another computable node
     * @param calculateAble
     */
    default void add(CalculateAble calculateAble) {}

    /**
     * Get product list
     * @return
     */
    default List<CalculateAble> getCalculateAbleList() {
        return null;
    }
}

Some specific goods

Next, we define some specific commodities, which are tree leaf nodes.

Apple

public class Apple implements CalculateAble {

    @Override
    public double calculate() {
        return 20;
    }

    @Override
    public String name() {
        return "apple";
    }
}

notebook

public class AlienWareNoteBook implements CalculateAble {
    @Override
    public double calculate() {
        return 25000;
    }

    @Override
    public String name() {
        return "alienWareNoteBook";
    }
}

milk

public class Milk implements CalculateAble {
    @Override
    public double calculate() {
        return 25;
    }

    @Override
    public String name() {
        return "Milk";
    }
}

Tea

public class Tea implements CalculateAble {
    @Override
    public double calculate() {
        return 99;
    }

    @Override
    public String name() {
        return "tea";
    }
}

order

There will be multiple products in an order, so the order object is a tree non leaf node

public class Order implements CalculateAble {

    private final List<CalculateAble> calculateAbles;
    private final String name;

    public Order(String name) {
        this.calculateAbles = new ArrayList<>();
        this.name = name;
    }

    @Override
    public double calculate() {
    	//The total price of the order and the sum of the prices of all items included in the order
        double sum = 0;
        for (CalculateAble calculateAble : calculateAbles) {
            sum += calculateAble.calculate();
        }
        return sum;
    }

    @Override
    public String name() {
        return name;
    }

    @Override
    public void add(CalculateAble calculateAble) {
        calculateAbles.add(calculateAble);
    }

    @Override
    public List<CalculateAble> getCalculateAbleList() {
        return calculateAbles;
    }
}

main

Finally, let's look at the main method

public class CompositeMain {
    public static void main(String[] args) {
	    //Create an order called order
        CalculateAble order = new Order("order");
        //Create an order called smallOrder
        CalculateAble smallOrder = new Order("smallOrder");
        //Add an item to smallOrder: Apple
        smallOrder.add(new Apple());
        //Add an item to smallOrder: tea
        smallOrder.add(new Tea());
        //Create an order called bigOrder
        CalculateAble bigOrder = new Order("bigOrder");
        //Add an item to bigOrder: notebook
        bigOrder.add(new AlienWareNoteBook());
        //Add smallOrder to order
        order.add(smallOrder);
        //Add bigOrder to order
        order.add(bigOrder);
        //Add milk to order
        order.add(new Milk());
        //Recursive printing tree
        loop(order, 0);
        //Calculate total price
        double calculate = order.calculate();
        System.out.println("The total price is:" + calculate);
    }

    private static void loop(CalculateAble calculateAble, int level) {
        if (level == 0) {

        } else if (level == 1) {
            System.out.print("├─");
        } else {
            for (int i = 0; i < level - 1; i++) {
                System.out.print("│ ");
            }
            System.out.print("├─");
        }
        System.out.println(calculateAble.name());
        List<CalculateAble> calculateAbleList = calculateAble.getCalculateAbleList();
        if (calculateAbleList != null) {
            for (CalculateAble able : calculateAbleList) {
                loop(able, level + 1);
            }
        }
    }
}

Finally, let's look at the implementation results:

From the results, we can see that the tree printed by the program is the same as the tree we drew at the beginning. There is no problem with the calculation of the total price.

summary

  1. If you want to deal with tree data, you can consider composite patterns
  2. If you want to handle simple objects (Apple, Tea, Alienware notebook, Milk) and complex objects (Order) in the same way, you can also use the composite mode

Keywords: Java Design Pattern

Added by erisande on Mon, 27 Dec 2021 13:59:09 +0200