--- Each mode is used to solve one or more types of problems, or to decouple the coupling relationship between certain objects, so that the tight coupling becomes a loose coupling relationship.
1. Preface (decoupling process)
After reading the previous "simple factory" Reading Notes, many of my friends may have a similar problem: Why did my notes only mention the advantages of a simple factory and do not mention any disadvantages? Here we will analyze the shortcomings or issues left over from the simple factory:
When we are used to simple factories, we like to apply simple factories to our own projects. For example, the simplest application is to create database connections or service layer interfaces. After a long time, we will find a problem:
Our requirements cannot remain unchanged. For example, let's take the example of fruit in a "simple factory:
We already have an apple, grape, and banana. What if the customer wants to eat pears? What should I do?
We will immediately think of adding a pear class. The Code is as follows:
View Code
1 public class Pear: IFruit
2 {
3 public string Name {get; set ;}
4 public string Skin {get; set ;}
5
6 public void Display ()
7 {
8 Console. WriteLine ("I Am a pear ");
9}
10}
Then, add a method to create a pear in a simple factory. If it is a parameter Factory (a factory in a simple factory, and an object created by a received parameter), it is better to do so, add a condition IF-ELSE To the method, and instantiate the object of the pear child. What ELSE do you want in the future? Are they added one by one?
Simple Factory Code:
View Code
1 public class OrchardFactory
2 {
3 public IFruit ProvideApple ()
4 {
5 return new Apple {Name = "Apple", Skin = "Green "};
6}
7 public IFruit ProvideBanana ()
8 {
9 return new Banana {Name = "Banana", Skin = "Yellow "};
10}
11 public IFruit ProvideGrape ()
12 {
13 return new Grape {Name = "Grape", Skin = "Grape "};
14}
15
16 public IFruit ProvidePear ()
17 {
18 return new Pear {Name = "pezi", Skin = "Pear "};
19}
20}
Parameter Factory Code:
View Code
1 public class ParmFactory
2 {
3 public IFruit ProvideFruit (string fruitName)
4 {
5 IFruit refFruit = null;
6
7 if ("Apple". Equals (fruitName ))
8 {
9 refFruit = new Apple {Name = "Apple", Skin = "Green "};
10} else if ("Banana". Equals (fruitName ))
11 {
12 refFruit = new Banana {Name = "Banana", Skin = "Yellow "};
13} else if ("Grape". Equals (fruitName ))
14 {
15 refFruit = new Grape {Name = "Grape", Skin = "Grape "};
16} else if ("Pear". Equals (fruitName ))
17 {
18 refFruit = new Pear {Name = "pezi", Skin = "Pear "};
19}
20
21 return refFruit;
22}
23}
From the code above, we can see that the problem that neither simple factory nor parameter factory can solve is that every time a new product appears, they must do two things: the first is to add a new product (here is the Pear class), and the second is that they will modify the logic in the factory object (add a creation method or modify the judgment logic in the method ), from the above question, we can see that the second thing is against the principle of open and closed (open to expansion and close to modification ).
Let's look at the simple factory structure.
Figure 1-1
From the above structure diagram, we can see that our simple factory was originally dependent on the tight coupling between the customer and the specific implementation, and then changed to the customer dependent on the factory and fruit interface. Here we get a prompt, we should rely on interfaces, and we will think of a sentence: "programming for interfaces, rather than programming for implementation ". When we try to define an interface, we think of a way that we can define an abstract (interface or abstract class). Why do we need to define such an abstract here? Because abstraction is stable for us, so that our client is dependent on abstraction, rather than on specific factories, each specific factory implements the product methods created in the abstract factory.
The abstract factory interface code is as follows:
View Code
1 public interface ifacloud
2 {
3 IFruit CreateFriut ();
4}
The specific implementation Factory Code is as follows:
View Code
1 /// <summary>
2 // Apple Factory
3 /// </summary>
4 public class AppleFactory: ifacloud
5 {
6 public IFruit CreateFriut ()
7 {
8 return new Apple {Name = "Apple", Skin = "Green "};
9}
10}
11
12 /// <summary>
13 // banana factory
14 /// </summary>
15 public class BananaFactory: ifacloud
16 {
17 public IFruit CreateFriut ()
18 {
19 return new Banana {Name = "Banana", Skin = "Yellow "};
20}
21}
22
23 /// <summary>
24 // grape Factory
25 /// </summary>
26 public class GrapeFactory: ifacloud
27 {
28 public IFruit CreateFriut ()
29 {
30 return new Apple {Name = "grape", Skin = "Purple "};
31}
32}
33
34 /// <summary>
35 // pear Factory
36 /// </summary>
37 public class PearFactory: ifacloud
38 {
39 public IFruit CreateFriut ()
40 {
41 return new Apple {Name = "Pears", Skin = "LightYellow "};
42}
43}
Code structure:
Figure 1-2
From the above structure diagram, we can see that the customer depends on the abstract factory and the abstract product. The previous step is to decouple the tight coupling relationship between the customer and the factory to the loose coupling relationship. The customer's dependence on specific factories has been transferred to the abstract factory, and because the abstraction is stable, the above problems have been solved. Here we use a very important principle in the design pattern: the Dependency inversion principle depends on abstraction rather than specific classes. It depends on everyone's understanding, but how is reverse understanding?
In the Head First design mode, we can see that the general OO design idea is the abstraction of the lower-level components and those dependent on the lower-level components, and then the higher-level master components also rely on the same abstraction. However, the factory (high-level components) depends on the IFruit interface (low-level components), and specific products such as Apple (low-level components) also depend on the IFruit interface (high-level components ). In this way, the dependency is reversed.
This leads to a design pattern "Factory method pattern ".
2. Summary
What is a factory method: defines an interface for creating objects, but the subclass determines which class is to be instantiated. The factory method delays the class Instantiation to the subclass.
The factory method mode is a creation mode.
3. structure chart analysis:
Figure 1-1 simple factory model diagram (supplement the previous dependency between customers and abstract fruits in a simple factory)
Figure 1-2 factory method mode structure diagram: transfers the tight coupling relationship between customers in a simple factory and a specific factory to the customer's dependency on the abstract factory, because the abstraction is stable, so we can solve the problem of adding new products and modifying the factory class.
4. Purpose:
The purpose of the factory method is:
From the perspective of dependency: decoupling the relationship between customers and specific products, turning them into loose coupling, and transferring the tightly coupled relationship to the abstract factory.
From the code point of view: Solve the simple factory violation of the open and closed principles, solve the problem of adding new products, do not modify the factory class.
5. application scenarios:
Abstract: different products (same product family) that meet product requestor, product provider, and provide the same parent class or interface ). If the above relationship exists, you can use a simple factory. However, it should be noted that if the requester requests, this situation is more suitable. That is to say, a simple factory is created like a database connection pool. because there are only a few fixed databases, the demand is relatively stable and the chance of modification is relatively small, so a simple factory can be used. However, it is not very suitable for creating service interfaces. For example, if I have a user authentication interface, I need to provide a log function after a period of development, the service layer needs to add a log interface. because the number of system modules is related to requirements, the number of interfaces is changed frequently. Therefore, the frequency of modification to the factory is very high. Therefore, it is more appropriate to use the factory method.
From the perspective of practical application: This method can be used together with other design modes for example, creating a connection pool for a database.