Definition: The dynamic of the responsibility attached to the object. To extend the functionality, decorated to provide a more flexible solution than inheritance.
1 cited cases _ coffee order system
1.1 was originally designed.
1, first create a Bevarage (drinks) abstract class, all in-store coffee inherit this class. description is a member variable, set by subclasses, describe coffee use. getDescription()
This description is returned. cost()
The method is an abstract method, implemented by a subclass, the price calculation used.
Initially there are the following four coffee (coffee not know, do not care about the Chinese name wrong): DarkRoast (super-excellent deep roasted coffee), Espresso (espresso), Decaf (low-calorie coffee), HouseBlend (mixed coffee)
But the request to add the coffee sauce: Milk (milk), Soy (soy milk), Mocha (Mocha), seasoning each has a separate price, so the design has added these, as shown.
Here we can see the problem, but in Figure 2 lists the three combinations, we can think about, this combination is a wide variety of coffee now four models, three kinds of seasoning, after taking into account, will be given introduce more coffee and various spices. So to maintain them, the class will explode, but some people still like to double copies of Mocha, such a calculation, then the class will be endless, and prices fluctuate, you will modify the price, so maintain them will be dead.
1.2 Further improvements
3, the seasoning added to the Bevarage
member variable, and adding the appropriate set and has methods, cost()
a method provided now implemented, the price calculated seasoning. Then calculate the final price by subclasses plus the price of coffee.
Despite this, we can see the problem:
(1) the type of seasoning, price changes, will affect the base class cost()
method.
(2) base class may bring many ways suited to a certain kind of coffee.
(3) the customer how to solve part of the double Milk.
This is contrary to the principles of design below.
Design principles: class should be open for extension, but closed for modification.
3.2 know the decorator pattern
1. FIG. 4: Example DarkRoast. Customers who ordered a glass DarkRoast, DarkRoast inheriting Beverage
class, you can call the cost()
method of calculating the price.
2. Figure 5: Customer plus a mocha sauce, then establish a Mocha object, wrapped in DarkRoast. Mocha is a decorator here, it's a type of decorative objects type of reaction, the reaction other words for that type of object and is decorated consistent.
3. Figure 6, the customer has added a milk foam sauce, then creating a Whip decorator, decoration just added a mocha coffee DarkRoast of.
4. FIG 7 checkout. Calls outermost cost()
method can be.
3.3 coffee order system
FIG class 3.3.1
1 Bevarage
is an abstract class, wherein cost()
the method is an abstract method.
2. four kinds of coffee are inherited Bevarage
.
3. Create a new abstract class seasoning CondimentDecorator
the four spices inherit this abstract class.
3.3.2 code implementation
1. Bevarage
, and four coffee.
public abstract class Beverage {
String description = "原味 咖啡";
public String getDescription() {
return description;
}
public abstract double cost();
}
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "DarkRoast";
}
@Override
public double cost() {
return 1.52;
}
}
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}
public class Decaf extends Beverage {
public Decaf() {
description = "Decaf";
}
@Override
public double cost() {
return 0.76;
}
}
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "HouseBlend";
}
@Override
public double cost() {
return 0.89;
}
}
2. abstract classes CondimentDecorator
and three spices.
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
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 0.20+beverage.cost();
}
}
public class Soy extends CondimentDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
public double cost() {
return beverage.cost() + 1.30;
}
}
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return beverage.cost() + 0.54;
}
}
3. test code.
public class StarbuzzCoffee {
public static void main(String[] args) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
Beverage beverage1 = new DarkRoast();
beverage1 = new Mocha(beverage1);
beverage1 = new Mocha(beverage1);
beverage1 = new Whip(beverage1);
System.out.println(beverage1.getDescription() + " $" + beverage1.cost());
Beverage beverage2 = new HouseBlend();
beverage2 = new Soy(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
}
}