Read headFirst design mode and headfirst Design Mode

Source: Internet
Author: User

Read headFirst design mode and headfirst Design Mode

Inheritance can extend the function of the parent class when the parent class code is reused. At the same time, inheritance increases the coupling between objects, so use inheritance with caution. Is there a way to expand the features of the parent class and decouple objects? The answer is yes. This is the Paster model we are going to learn today. Later you will see that I will assemble a computer in the decorating mode. But now I want to learn the examples in the book first.

 

Examples in learning books

The Starbuzz coffee shop system needs to be updated. Their original system is as follows:

 

We can see that the customer provides a specific sub-class when purchasing a beverage and returns the price of the beverage. When purchasing coffee, you can add some spices, such as Steamed Milk, Soy, Mocha or chocolate flavor, or overwrite Milk. Starbuzz charges different fees based on the added spices. So how can this be done? We may think of the following solutions:

1. List the combinations of all drinks and spices. Well, I don't think anyone will do this. There are too many combinations like this. In the book, this is called "class explosion ".

2. in the Beverage class, set the boolean value of various spices to indicate whether such spices are required, such as boolean milk. Then, use cost to calculate the price after adding various spices, then, the cost method of the parent class is called in the cost method of the subclass and the price of the beverage is added.

Analysis in 2nd: It sounds good, but once you add a new seasoning, You have to modify the Beverage class. If a new type of beverage is found, some spices may not be suitable, which leads to the method for adding inappropriate spices to the beverage. What are the consequences, this may lead to some bad consequences. In the policy model chapter, we have learned a lesson (the Rubber Duck will fly ). What should I do if I want to double Moka?

 

Try to solve the problem

Now the problem has emerged. How can this problem be solved? It is natural that people buy coffee in the following State: buy a cup of coffee first, and then buy whatever spices they want. So we want to solve the problem: first create a cup of coffee, then create a seasoning and combine it with the dynamic combination of coffee. By dynamically combining objects, you can write new code and add new features without modifying existing code. Since the existing code is not changed, the chances of introducing bugs or unexpected side effects will be greatly reduced. This requires the modifier mode.

 

Software Design Principles

Open-Close principle: the class should be open to the extension and closed to the modification.

 

Define the decorator Mode

Dynamically attaches the responsibility to the object. To expand the functionality, the decorator provides an alternative solution that is more flexible than inheritance.

 

Bring Starbuzz drinks in the decorator Mode

You need to explain this figure: the Beverage class is the abstract class of the Beverage. All the drinks must inherit from this class. It has a method (getDescription () to obtain the description ()) and an abstract method for price calculation, cost (). Four specific coffee classes (such as Espresso) inherit the Beverage class and override the cost method. The CondimentDecorator class is an abstract decoration class that inherits Beverage and Milk. It is a specific decoration class. When calculating the price, it adds the seasoning price to the Beverage price, when a description is obtained, the seasoning description is added to the beverage description. Therefore, the modifier adds behavior to the object of the decorator.

As mentioned above, we should use inheritance with caution. The modifier mode adds new functions through dynamic composite objects. Why does the CondimentDecorator class inherit the Beverage class? In fact, here inheritance is not used to inherit behaviors, but to maintain type matching. That is to say, you can replace it with the modifier type when you need the modifier type. This may not be quite clear. For example, CondimentDecorator does not inherit Beverage: if the customer orders a cup of Espresso coffee Espresso, the spices to be added are Milk and Mocha, we need to first create a cup of Espresso to get the espresso object, and then pass in the espresso object as the parameter to create the Milk object, CondimentDecorator milk = new Milk (espresso ); in this way, milk is added to coffee concentrate, But MoKA needs to be added. Therefore, CondimentDecorator inherits Beverage to maintain type matching.

 

Start work

First, abstract drinks and specific drinks are required.

Beverage:

/*** Abstract Beverage class */public abstract class Beverage {protected String description = "Unknow Beverage"; // public String getDescription () {return description ;} // calculate the price public abstract double cost ();}
View Code

 

Espresso:

/*** Espresso */public class Espresso extends Beverage {public Espresso () {description = "Espresso" ;}@ Override public double cost () {return 1.99 ;}}
View Code

A specific drink only has its own description and Price. For details about other drinks, see the following:Appendix

Then, the abstract decorator and the specific decorator are added. The specific seasoning decorator attaches his own price and description to the price and description of the beverage.

 

CondimentDecorator:

/*** Enter your own description for the seasoning. */public abstract class CondimentDecorator extends Beverage {public abstract String getDescription ();}
View Code

 

Mocha, the modifier for specific spices:

/*** Moka, inherited from the seasoning modifier */public class Mocha extends CondimentDecorator {private Beverage beverage; public Mocha (Beverage beverage) {this. beverage = beverage;} @ Override public String getDescription () {return beverage. getDescription () + ", Mocha" ;}@ Override public double cost () {return 0.20 + beverage. cost ();}}
View Code

For details about other spices, refer to the following section.Appendix B

In fact, we can see that the Beverage object is referenced in each specific adjustment class. Since we can put the Beverage object reference in the CondimentDecorator class, you can adjust it by yourself. I will not adjust it here. I will put the reference of the decoration class into the abstract decoration class in the example of assembling the computer later.

 

Test DecoratorTest:

/*** The modifier should add behavior to the encapsulated object */public class DecoratorTest {public static void main (String [] args) throws Exception {Beverage darkRoast = new DarkRoast (); System. out. println (darkRoast. getDescription () + "\ t" + darkRoast. cost (); System. out. println ("-------------------"); Beverage espresso = new Espresso (); espresso = new Mocha (espresso); espresso = new Soy (espresso ); system. out. println (espresso. getDescription () + "\ t" + espresso. cost ());}}
View Code

 

What do the decorator do:

In the example, we can see that the modifier should add behavior to the encapsulated object.

 

Decorator in jdk:

Jdk also uses the modifier mode, which is used in the IO stream. I think it is quite painful for everyone to learn IO streams. They may not only distinguish between byte streams and hidden streams, but also attempt to confuse our sights with decorative streams. For example, BufferedInputStream is a decorative stream that can be used to describe FileInputStream. Therefore, the most common form is new BufferedInputStream (new FileInputStream (new File (""))); similar to what we mentioned above, the decorative stream also adds some behavior to the decorated object. For example, BufferedInputStream improves the performance by buffering arrays, provides a readLine method to read the entire row for expansion. The figure below gives you a better understanding of the decorator in the IO stream:

In this figure, byte streams are listed, and hidden streams are similar. However, the decorative stream adds more classes in IO, which may sometimes cause us troubles. If you have to say so, this is also a "disadvantage ";

 

Write your own example

After learning the examples in the book, I always want to give an example by myself. However, it is really difficult to find a suitable example. This is "when books are used, there is little hate "? Haha, don't talk about it. Let's take a look at my own example: I want to assemble a computer. Now there is only one chassis, and other accessories need to be added. Here is an example.

 

Hands-on computer assembly

First, a Computer Abstract class Computer is required. There are two Abstract METHODS: model type and price price2. There are two abstract methods to obtain the components comprise () and calculate the total prices:

/*** Abstract class of the Computer, abstract class of the decoration class */public abstract class Computer {private String type; // model private Double price; // price public abstract String comprise (); // component public abstract Double prices (); // Total public String getType () {return type;} public void setType (String type) {this. type = type;} public Double getPrice () {return price;} public void setPrice (Double price) {this. price = price ;}}
View Code

 

Assume that there is only one first-horse chassis as the decorator.SAMAChassis:

/*** A specific first-horse chassis decorated with classes */public class SAMAChassis extends Computer {public SAMAChassis () {setType ("first-horse chassis"); setPrice (136.0 );} @ Override public Double prices () {return getPrice () ;}@ Override public String comprise () {return getType ();}}
View Code

 

Now you need to add CPU, motherboard, memory and other accessories to the network chassis, and use these accessories as decorations to deploy the chassis. An abstract class of the modifier is required.DiyDecorator:

/*** Abstract decoration, diy accessories, and various accessories have models and prices, so they are processed in abstract parent classes, other attributes are temporarily excluded */public abstract class DiyDecorator extends Computer {private Computer computer; public String comprise () {// here this represents a specific modifier subclass, optional return computer. comprise () + "---" + this. getType ();} public Double prices () {return computer. prices () + this. getPrice ();} public DiyDecorator (Computer computer) {this. computer = computer;} public DiyDecorator (Computer computer, String type, Double price) {this. computer = computer; this. setType (type); this. setPrice (price );}}
View Code

 

Here we design a problem mentioned above. I put the reference of Computer into the abstract class DiyDecorator to increase code reuse. The comprise and prices methods are also implemented. In this way, the subclass only needs to call the constructor of the parent class.

Speaking of this, another question arises: we know that the object of the abstract class cannot be created. So why is there a constructor for the abstract class? In fact, we can see from this example that the constructor of abstract classes is used to instantiate member variables.

 

Specific decorative CPU:

/*** Specific decoration class: CPU class */public class CPU extends DiyDecorator {public CPU (Computer computer, String type, Double price) {super (computer, type, price );} public CPU (Computer computer) {super (computer );}}
View Code

I will not write any other specific decoration classes or the appendix, which is very simple.

 

Test DecoratorTest:

/*** We are now assembling a computer. There is only one chassis at first, and nothing else */public class DecoratorTest {public static void main (String [] args) {run1 (); System. out. println ("------------------"); run2 ();} private static void run1 () {Computer computer = new SAMAChassis (); computer. setType ("jinhetian foresight"); computer. setPrice (215.0); computer = new CPU (computer, "core i5 4590", 999.5); System. out. println (computer. total price of comprise () + "\ t:" + computer. prices ();} private static void run2 () {SAMAChassis chassis = new SAMAChassis (); CPU cpu = new CPU (chassis); cpu. setType ("core i5"); cpu. setPrice (999.0); Mainboard mainboard = new Mainboard (cpu); mainboard. setType ("gigabyte B150"); mainboard. setPrice (636.5); Memory memory = new Memory (mainboard, "Kingston 8g", 412.5); Power computer = new Power (memory, "500 w", 435.0 ); system. out. println (computer. total price of comprise () + "\ t:" + computer. prices ());}}
View Code

 

Summary

The modifier mode dynamically attaches the responsibility to the object. To expand the functionality, the decorator provides an alternative solution that is more flexible than inheritance. The modifier mode complies with the open-close principle: it is open to the extension and closed to the modification.

 

 

Appendix

Deep coffeeDarkRoast:

/***** Deep coffee */public class DarkRoast extends Beverage {public DarkRoast () {description = "DarkRoast" ;}@ Override public double cost () {return 0.99 ;}}
View Code

 

Low caffeine coffeeDecaf:

/***** Low-caffeine coffee */public class Decaf extends Beverage {public Decaf () {description = "Decaf" ;}@ Override public double cost () {return 1.05 ;}}
View Code

 

Integrated coffeeHouseBlend:

/*** Coffee */public class HouseBlend extends Beverage {public HouseBlend () {description = "HouseBlend" ;}@ Override public double cost () {return 0.89 ;}}
View Code

 

 

Appendix B

Soy milkSoy:

/*** Soy milk */public class Soy extends CondimentDecorator {private Beverage beverage; public Soy (Beverage beverage) {this. beverage = beverage;} @ Override public String getDescription () {return beverage. getDescription () + ", Soy" ;}@ Override public double cost () {return 0.15 + beverage. cost ();}}
View Code

 

Milk bubbleWhip:

/*** Specific modifier, milk bubble */public class Whip extends CondimentDecorator {private Beverage beverage; public Whip (Beverage beverage) {this. beverage = beverage;} @ Override public String getDescription () {return beverage. getDescription () + ", Whip" ;}@ Override public double cost () {return 0.10 + beverage. cost ();}}
View Code

 

Related Article

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.