Head First design pattern decorator mode (Decorator pattern)

Source: Internet
Author: User

Objective:

This section will discuss inheritance abuse in depth, and will learn how to use object composition to decorate classes at run time and assign new responsibilities to objects without modifying any of the underlying code.

1. Basic needs: Coffee chain business expansion needs to redesign the order system

Background: Due to the expansion of the Starbuzz coffee chain business, the order system is ready to be updated to meet their beverage supply requirements.

Their original class was designed as follows:


When you buy coffee, you can ask to add a variety of spices to the coffee, Starbuzz will charge different fees according to the different users to join, the New Order system must take into account these seasoning parts.

1.1 Design for the first time

The cost () method for each of the above classes will calculate the price of the coffee plus the various seasonings for the order. Although it can meet the requirements, it will require many and many classes, but also violate the OO design principles.

1.2 Second time design

There is no need to create so many classes, just by using instance variables and inheritance, you can trace the seasoning.

The design is as follows:


In doing so, you can actually meet the requirements temporarily, but there are some potential pitfalls, as follows:

L Spice Price Changes will change the original code

New seasoning, in addition to adding new methods, you also need to change the cost () method in the Super class

L dependency inheritance, subclasses will inherit some methods that are not appropriate for themselves

L Part of the demand is not satisfied: such as double mocha Coffee

L violated the open-close principle

2. Introduction of Decorator Mode 2.1 development----closure principle

In the second design of the previous section, we can see that this design method clearly violates the "development-close" principle, what is the open and closed principle? Defined as follows:

Development-Shutdown principle: Classes should be open to extensions and closed to modifications.

Our goal is to allow classes to be easily extensible, with new behaviors that can be paired without modifying existing code, so that the design is resilient to change and can accept new functionality to respond to changing needs. Following the open-and-close principle, it is common to introduce new levels of abstraction, increase the complexity of your code, choose where you are most likely to change in your design, and then apply the development-closure principle.

2.2 Recognize decorator patterns and construct beverage orders with decorators

In 1 we have learned that inheritance does not completely solve the problem, here we take the beverage as the main body, and then in the run with seasoning to "decorate" the drink. For example: If the customer wants mocha and milk foam deep roasted coffee, as follows:

L Take a deep bake (darkroast) object

L Decorate it with mocha (Mocha) object

L decorate it with a milk bubble (Whip) object

L Call the Cost () method and rely on the delegate (delegate) to add the price of the seasoning

Description: Starting with the Darkroast object, the customer wants Mocha (Mocha), so set up a Mocha object, use it to wrap the Darkroast object, the customer wants the Milk cannon (Whip), so you need to create a Whip decorator, and use it to wrap the Mocha objects together. At the end of the calculation, it can be done by invoking the cost () method of the outermost decorator whip. Its invocation process is as follows:

Whip.cost () Àmocha.cost () Àdarkroast.cost () (return darkroast price) àmocha.cost (Mocha add your own price to Darkroast) Àwhip.cost () (Whip add his own price to the results of Mocha's return)

Based on the above analysis, we can draw the following conclusions:

Decorators and decorated objects have the same super-type.

You can wrap an object with one or more decorators.

Because the decorator and the decorator have the same super-type, you can replace it with a decorated object in any situation where the original object is needed.

The decorator may, before or after the act entrusted to the decorator, add his or her own behavior to achieve a specific purpose.

Objects can be decorated at any time, so you can decorate objects dynamically with your favorite decorators at run time.

2.3 Defining Decorator Mode

Decorator Mode:

The decorator provides a more resilient alternative to dynamically attaching responsibilities to objects to extend functionality.

The design class diagram is as follows:


Based on the class diagram of this decorator pattern, we designed the class diagram of Starbuzz and made it conform to this structure design, the class diagram is as follows:


Decorators and decorators inherit from the beverage class, which is the common superclass, where we use inheritance to achieve "type matching" rather than using inheritance to get "behavior".

When a decorator and a component are combined, the new behavior is added, and the resulting new behavior is not inherited from the superclass, but by the combined object.

If you rely on inheritance, the behavior of the class can only be statically determined at compile time, not from the superclass, but from the overwritten version of the subclass, and to modify the existing code whenever new behavior is required. If you use a combination, you can dynamically implement new decorators to add new behavior.

3 using decorator mode for coffee shop requirements

Based on the class diagram of the coffee shop designed in 2.3, the following is a specific code implementation:

3.1 Beverage Class (abstract component)
Description:beverage abstract class///    </summary> Public    abstract class Beverage {public        string Description = "Unknownbeverage";        public abstract stringgetdescription ();         public abstract double Cost ();     }
3.2Condiment (seasoning) base class (Inherit from beverage base class, abstract decorator)

Description: Seasoning base class, derived class///    </summary> public    abstract class Condimentdecorator:beverage    {        Public  Abstract String getdescription ();    }

3.3 Beverage Class (Inherit beverage base class, specific components)

public class Espresso:beverage {public Espresso () {description = "Espresso";//Set the description of the drink, DESCRI        Ption inherits the instance variable from the beverage class} public override double cost () {return 1.99;        } public override string GetDescription () {return description; }} public class Houseblend:beverage {public houseblend () {description = "Houseblen        D ";        } public override double cost () {return 0.89;        } public override string GetDescription () {return description;         }} public class Darkroase:beverage {public darkroase () {description = "darkroase";        } public override double cost () {return 1.11;        } public override string GetDescription () {return description; }} public class Decat:beverage {PUBlic Decat () {description = "Decat";        } public override double cost () {return 1.22;        } public override string GetDescription () {return description; }    }

3.4 Seasoning (decorator)

public class Mocha:condimentdecorator {beverage beverage;        Public Mocha (Beverage beverage) {this.beverage = beverage; } public override string GetDescription () {return beverage.        GetDescription () + ", Mocha"; } public override double cost () {return 0.2 + beverage.        Cost ();        }} public class Soy:condimentdecorator {beveragebeverage;        Public Soy (Beverage beverage) {this.beverage = beverage; } public override string GetDescription () {return beverage.        GetDescription () + ", Soy"; } public override double cost () {return 0.3 + beverage.        Cost ();        }} public class Whip:condimentdecorator {beverage beverage;        Public Whip (Beverage beverage) {this.beverage = beverage;  } public override string GetDescription () {          Return beverage.        GetDescription () + ", Whip"; } public override double cost () {return 0.3 + beverage.        Cost (); }    }

3.5 Testing

Beverage.beverage beverage = Newbeverage.espresso ();            Console.WriteLine (beverage. GetDescription () + "$" + beverage. Cost ());             Beverage.beverage beverage1 = Newbeverage.darkroase ();            Beverage1 = new Beverage.mocha (beverage1);            Beverage1 = new Beverage.mocha (beverage1);            Beverage1 = new Beverage.whip (beverage1);            Console.WriteLine (Beverage1. GetDescription () + "$" + beverage1. Cost ());             Beverage.beverage beverage2 = Newbeverage.houseblend ();            Beverage2 = new Beverage.soy (beverage2);            Beverage2 = new Beverage.mocha (beverage2);            Beverage2 = new Beverage.whip (beverage2);            Console.WriteLine (Beverage2. GetDescription () + "$" + beverage2. Cost ());

Results such as:


4 Summary

Through this chapter, we can learn the following knowledge:

L OO principles:

Package changes

Multi-use combination, less inheritance

Programming for interfaces, not for implementation

Strive for loosely coupled design between interacting objects

Open to extensions, closed for modification (OO principles for new learning in this chapter)

L OO Mode

Decorator mode-dynamically attaches responsibility to the object and wants to extend the functionality, and the decorator provides an alternative to inheritance.

L Main points Induction

Inheritance and decorators can allow us to extend behavior, but inheritance is not the best solution for elastic design.

Decorator mode means a group of decorator classes, the Decorator class reflects the type of component being decorated, and can be packaged with multiple decorators.

The decorator may add his or her behavior before or after the act of the decorator, or even replace it with the act of the decorator for a specific purpose.

Decorator mode causes many small objects to appear in the design, and overuse can complicate the program.

Decorator mode for Head first design mode (Decorator pattern)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.