To consider

There are the following types of design:



What if the price of milk goes up? What happens when you add a caramel flavor?

What design principle did we mention earlier violate by creating this maintenance difficulty?P82

  • Take out and encapsulate the changed parts, leaving the rest untouched
  • Use composition more than inheritance

To consider

Write code for the cost() method of the following class. P83

public class Beverage {
    public double cost(a) {
        double totalCost = 0.0;
        
        if (hasMilk()) {
            totalCost += milkCost;
        }
        if (hasSoy()) {
            totalCost += soyCost;
        }
        if (hasMocha()) {
            totalCost += mochaCost;
        }
        if (hasWhip()) {
            totalCost += whipCost;
        }
        
        returntotalCost; }}Copy the code

Concrete class: DarkRoast

public class DarkRoast extends Beverage {
    public DarkRoast(a) {
        description = "Most Excellent Dark Roast";
    }
    
    public double cost(a) {
        return baseCost + super.cost(); }}Copy the code

To consider

What requirements or factors will affect the design when it changes? P84

  • The change in seasoning price will cause us to change the existing code
  • As soon as we have a new seasoning, we need to add a new method and change the cost() method in the superclass
  • New drinks may be developed later. For these drinks (e.g., iced Tea), some seasonings may not be appropriate, but in this design, the Tea subclass will inherit methods that are not appropriate, e.g., hasWhip().
  • What if the customer wants a double mocha or coffee?
  • Condiments vary with the specific drink
  • The base price of drinks varies from large to medium size

Design principles

  • The open closed principleClasses should be open for extension and closed for modificationP86
    • Policy mode, Observer mode, and decorator mode all follow the open and closed principleP105

Decorator mode

Dynamically attaching responsibility to an object without changing its original code. Decorators provide a more resilient alternative to inheritance when extending functionality.P91

The characteristics of
  • Decorator classes and decorated classes have the same supertypeP90
  • A decorator class can precede (or follow) the behavior of the delegated decorator class by adding its own behavior to achieve a specific purposeP90
  • Decorators can be inserted transparently and used without even knowing that you are interacting with themP104
  • Suitable for creating flexible designs that maintain open and close principlesP104
disadvantages
  • There are a large number of small classes that can increase code complexity when usedP101 P104
  • Rely on a particular type for use, and then suddenly import decorators without thinking everything throughP104
To consider

Our friends at Starbaz decided to start adding coffee sizes to the menu so customers could choose from tall, Grande, venti. Starbaz believes this is a must for any coffee, so getSize() and setSize() have been added to the Beverage category. They also want condiments to be charged according to the size of the coffee, such as $0.10, $0.15 and $0.20 for small and large cups of coffee plus soy milk. How can decorator classes be changed to meet this need? P99

public class Soy extends CondimentDecorator {
    Beverage beverage;
    
    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }
    
    public int getSize(a) {
        return beverage.getSize();
    }
    
    public void setSize(int size) {
        beverage.setSize(size);
    }
    
    public String getDescription(a) {
        return beverage.getDescription() + ", Soy";
    }
    
    public double cost(a) {
        double soyCost = 0.0;
        
        switch (getSize()) {
            case TALL:
                soyCost = 0.10; 
                break;
            case GRANDE:
                soyCost = 0.15; 
                break;
            case VENTI:
                soyCost = 0.20; 
                break;
            default:
                soyCost = 0.0;
        }
        
        returnbeverage.cost() + soyCost; }}Copy the code

thoughts

  • The decorator pattern uses inheritance (or implements interfaces), so when supertypes add methods, all subclasses need to change, and design with that in mind
  • Always feel familiar decorator pattern, lookjava-design-patterns/decoratorLater,The idea of discovering decorator patterns is typically implemented using AOP(Finally learned the proxy mode to discover the original dynamic proxy mode)

This post is posted on GitHub: Reading-Notes/Head-First-Design-Patterns