@TOC
1. Cafe order system project
1. Cafe Order System Project:
Espresso, ShortBlack, LongBlack, Decaf (sugar free) (these are the basis of equivalent coffee, single coffee, basic elements, all coffee is mixed on this basis) Milk, Soy, Chocolate (add Milk, Chocolate, etc., to the basic varieties, to form similar Chocolate flavored coffee, mocha, caffe chino, etc. When we go to a coffee shop, we usually order a caffe cino, which is the price of a single coffee and all the seasonings together. Therefore, the following case system is the complete coffee system. (3) The design principle (or requirement) of the coffee shop order project: good scalability, convenient change, convenient maintenanceCopy the code
2. The traditional way — simply through the OO model
Is to design all coffee or spices into one superclass; As shown in the figure, all drinks are designed as an abstract superclass Drink, with a variable description description, which is actually the name of coffee, the name of seasoning, etc. There is also a method called getDescription() that calls this class to specify what type of coffee it is. Finally, cost() is an abstract method, which can be realized in specific single coffee, such as the price of single coffee or the price of single coffee with seasoning. And the individual coffees up here implement this abstract class, implement description to represent the specific thing which individual class of coffee gives you the specific type. Classes like Decaf are known from new. So cost is just going to return how much money. The code implementation is the user new a single coffee Decaf. Then call getDescription () to get the Decaf order, and call cost to get the cost.
So what do you do when you add a variety of spices, like a mocha? In fact, it is the same, as shown below:Copy the code
For example, when extending the Drink class, it calls description to indicate which flavorings I’m adding, such as Espresson’s several implementations that indicate adding sugar and soy milk. Cost () is also directly calculated to indicate the total amount of money. When the user calls Espresson, Milk and Soy, cost will directly return the amount of money. Three coffees are implemented.
But the problem is, seasoning has a lot of, which combination can be set, which combination can not be set, you have to maintain their own. To add a singleton type later, add a new class that implements the Drink class. If you want to add spices, you need to combine them differently, which will produce a lot of classes. This will explode, introducing that if the price of a single item changes, the associated combination will change accordingly. So let’s do it a little bit better.
3. A slightly better design (don’t look)
The idea is to build all the ingredients into the superclass. Add some of the ingredients above, but they are all Boolean, and the methods defined below are used to determine whether to extend the class to have them, or what to add, and whether to add money. This solution will be better than the last one, it will not explode, but it also has some problems
(1) Add or delete condiments. If a condiment is to be introduced, the superclass must be changed. That is, the introduction of new features, it affects the old features, the old code. So when you make changes to an existing feature, all of those things are going to be buggy, all of them are going to be buggy. And no soy milk will modify the superclass.
(2) Adding multiple copies of the problem, for example, if two milk is introduced, the Boolean type can not be judged.
Two, decorator mode principle
1, decorator mode principle
Decorator mode is like packing a package; Let's say I sell a piece of pottery, a book, and the core of that is what we sell. We can't sell these things directly, so we put a lot of protective packaging on the outside, like foam and so on. Main body: ceramic, clothing packaging: newspaper filling, plastic foam, cardboard, wood so decorator pattern can also be understood in this way. It is like the abstract superclass of the Drink example above. (Component: What is the body of the decoration?) (2) ConcreteComponent: Concrete themes of different types (ceramics to sell, clothes, etc.), like the single coffee above, for packaging objects. A Decorator (styrofoam, cardboard, etc.) that acts like a variety of spices.Copy the code
The above is the class structure implementation, if the topic is more complex, you can also add a buffer class between the topic and the entity, that is, the common methods of the topic out of the topic and the entity. Add another abstract class. Then implement the concrete entity class. This is designed on a case-by-case basis. This time the coffee design is relatively simple, there is no need to introduce a middle layer. When a body component is extended to a concrete implementation class, a decorator introduces an intermediate layer that brings in the decorator’s exposed part. When a concrete implementation is introduced, it only needs to implement its own specific part. The public ones are up there, in the middle.
Decorator pattern definition
Dynamically append new functionality to objects. It is more flexible than inheritance in extending object functionality. To put it simply: from the above example, the object here actually refers to single-serve coffee. The added function is various seasonings, which makes single-serve coffee taste better. This means that the decorator mode can dynamically add seasonings to individual coffee blends to make a good coffee. And it’s added by attachment, not inheritance.
Iii. New project design scheme
1. Design the redesign scheme with decorator pattern
Here, the subject and the entity remain roughly the same, with an intermediate layer added between the abstract subject and the seasoning. The function of the middle layer is that when cost is called, cost is superimposed. Another important thing is that the middle layer introduces a Drink object, which actually contains the object to be decorated. The decorated object will get its cost when we call coat. We then recursively fetch all the costs for this level, while the name of the specific decoration can be obtained by getDescription (). Even if there are so many things packaged outside, it can also be obtained.
2. Example orders in decorator mode
LongBlack with 2 chocolate and 1 milkCopy the code
So how do we do that? First, a single product object LongBlack is created, and then it is packaged to Milk and then Chocolate. The specific cost is calculated by using the outermost cost method instead of cost, which will obtain the cost of its own packaging and then recurse step by step. To call all costs to get all costs; And by structuring it this way, you can see that when we have a lot of spices, any combination we want, we can get all the expenses in this recursive way. Unlike the first approach, each new combination expands a class, resulting in a class explosion. And when you introduce a condiment, you only need to expand one of the specific condiments mentioned above. When you introduce a new condiment, the original function will not be affected. It introduces itself and doesn’t affect the original code.
Four, decorator model example demonstration
1. The overall design scheme of decorator mode
2. Code implementation
1. com ponent class
public abstract class Drink { public String description; Private float price = 0.0 f; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } public abstract float cost(); }Copy the code
2. ConcreteComponent class
Buffer layer coffee class
public class Coffee extends Drink{ @Override public float cost() { return super.getPrice(); }}Copy the code
Decaf class, LongBlack class, ShortBlack class, Espresso class
public class Decaf extends Coffee{ public Decaf() { super.setDescription("Decaf"); Super. SetPrice (3.0 f); } } public class LongBlack extends Coffee { public LongBlack() { setDescription(" longblack "); SetPrice (5.0 f); } } public class ShortBlack extends Coffee{ public ShortBlack() { setDescription(" shortblack "); SetPrice (4.0 f); }} public class Espresso extends Coffee {public Espresso() {setDescription(" Espresso "); SetPrice (6.0 f); }}Copy the code
3. The Decorator classes
Milk, Chocolate and Soy
public class Milk extends Decorator { public Milk(Drink obj) { super(obj); SetDescription (" milk "); SetPrice (2.0 f); } } public class Chocolate extends Decorator { public Chocolate(Drink obj) { super(obj); SetDescription (" chocolate "); SetPrice (3.0 f); } } public class Soy extends Decorator{ public Soy(Drink obj) { super(obj); SetDescription (" soya-bean milk "); SetPrice (1.5 f); }}Copy the code
4. The Test class
Public static void main(String[] args) {public static void main(String[] args) { LongBlack Drink order = new LongBlack(); System.out.println(" cost 1=" + order.cost()); System.out.println(" Description =" + order.getDescription()); Order = new Milk(order); System.out.println("order =" + order.cost()); System.out.println("order adds a description of the milk = "+ order.getDescription()); // 3. Order = new Chocolate(order); System.out.println("order =" + order.cost()); System.out.println("order add milk add chocolate description = "+ order.getDescription()); // 3. Order = new Chocolate(order); System.out.println("order add 1 milk add 2 chocolate cost =" + order.cost()); System.out.println("order add 1 milk add 2 chocolate description = "+ order.getDescription()); System.out.println("==========================="); Drink order2 = new Decaf(); Println ("order2 free coffee cost =" + order2.cost()); Println ("order2 = "+ order2.getDescription()); system.out.println ("order2 =" + order2.getDescription()); order2 = new Milk(order2); System.out.println(" Order2 + milk cost =" + order2.cost()); System.out.println(" Order2 add a description of milk to coffee = "+ order2.getDescription()); }Copy the code
Five, decorator mode principle
Open – close principle of design, meaning: decorators add new functions, such as adding a seasoning, open is to add a new function, close is to add a new function, the original code is not easy to change. In other words, when designing a project architecture, new code is open to the addition of new features, and no modifications are allowed to code that has already been designed or tested.
6, Java built-in decorator introduction (wait to see)
Java IO decorator
This is actually the same as the above cafe design.
FileInputStream and so on are subjects, where FilterInputStream is an intermediate layer that inherits some common things, and below that are decorators.
2. Write your own Java I/O decorator
Implement your own decorator object using the FilterInputStreamsh middle layer of extended Java
This example function converts a string input from a file input stream or other body input stream to uppercase
import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; Public class UpperCaseInputStream extends FilterInputStream{ Protected UpperCaseInputStream(InputStream in) {super(in); // TODO auto-generated constructor stub} Public int read() throws IOException// Single-character read {int c=super.read(); // super.read() calls super(in); Return c==-1? c:Character.toUpperCase((char)(c)); } public int read(byte[] b,int offset,int len) throws IOException {int result=super.read(b,offset,len); for(int i=0; i<result; i++) { b[i]=(byte)Character.toUpperCase((char)(b[i])); } return result; } } import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; public class InputTest { public static void main(String[] args) { int c; try { InputStream in = new UpperCaseInputStream(new BufferedInputStream( new FileInputStream("F:\\test.txt"))); while((c=in.read())>=0) { System.out.print((char)c); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }}}Copy the code