"HeadFirst Design Patterns" Chapter 3 - Decorator Pattern - reading notes
Case Code links: https://github.com/rainweb521/My-tutorial/tree/master/Design_patterns
background
This time is Starbuzz coffee, they need a new order system, the original design was too redundant, directly using an abstract class as a parent class beverages, other spices to increase process inherits the parent class sub-class, and then later realize, this becomes particularly complicated, there is no way to maintain.
Violation of the design principles laid down before:
- Multi-purpose combination, less inheritance.
- An interface for programming, not for the realization of programming.
A first solution
Implementation process
Beverage direct overwrite type, all the spices are written into, into a boolean value, it is determined in the parent's cost, and adds these spices.
Subclass continue after the parent class, override the cost method, with their price plus the cost calculation of the price of the parent class.
This whole complete new design.
There is still a problem
When what the needs or factors change, it will affect the design?
- Seasoning price changes will make us change the existing code.
- Once the new spices emerge, we need to add new methods, and change cost () method in the superclass.
- You may later develop a new drink. For these beverages (for example: iced tea), some spices may not be suitable, but in the design mode, Tea (tea) subclass will inherit those methods are not suitable, for example: hasWhip () (with milk bubble).
- In case the customer wants to double mocha, how do
Design Principles
Class should be open for extension, but closed for modification.
Design Patterns
Decorator Pattern : dynamically responsibility attached to the object. To expand the capabilities decorated to provide a more flexible than inheritance alternative.
The second solution
1. We do the processes
- Take a deep roasted coffee (DarkRoast) objects
- With Mocha (Mocha) objects decorate it
- With milk foam (Whip) it decorative objects
- Call cost () method, and relies on trust (delegate) will add to the price of spices
2. Analog decoration process
note:
- Decorator and decorated objects have the same super type.
- You can wrap an object with one or more decorators.
- Since the decorator and the decorated objects have the same supertype, so any desired original object (packaged) in the case, the object can be decorated with it in place.
- Decoration can be decorated before the behavior of those entrusted with / or after, with their own behavior in order to achieve a specific purpose.
- Objects can be decorated at any time, so you can dynamically at run-time, limited quantity to decorate objects with the decorators you like.
An analog implementation class 3. FIG.
note:
Here it is used the inheritance, Beverage abstract class, in order to have the correct type, rather than inherit its behavior. Decorator and behavior from the basic components, or a combination of the relationship between the other decorators.
4. DETAILED code implementation
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
public class Espresso extends Beverage {
public Espresso(){
description = "Espresso";
}
public double cost() {
return 1.99;
}
}
public class HouseBlend extends Beverage {
public HouseBlend(){
description = "HouseBlend";
}
public double cost() {
return 0.89;
}
}
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ",Mocha";
}
public double cost() {
return .20+beverage.cost();
}
}
public class StarbuzzCoffee {
public static void main(String[] args) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()+" $ "+beverage.cost());
Beverage beverage1 = new HouseBlend();
beverage1 = new Mocha(beverage1);
System.out.println(beverage1.getDescription()+" $ "+beverage1.cost());
}
}