The design pattern can make our code more flexible, easier to expand, and easier to maintain. Various Object-Oriented Programming Languages provide basically the same mechanism, such as classes, inheritance, derivation, and polymorphism. However, they have their own characteristics. The reflection mechanism in C # is a very important tool, which can play a major role in practice.
Let's look at an example:
My program needs a series of objects, such as apple, orange ..., To use them, we must generate them in the program based on user requirements and call the new operator one by one so that the client program will know the information of the corresponding class, the generated code is obviously not flexible enough. We can not use specific classes in the code, but simply describe what we need, and then we can get the object we want?
Oh, we all look at the design patterns. Let's listen. Many people are there preaching how they are doing well. Let's look at how to use them to solve the problem. If the goal is clear, let's see which one meets our requirements. I have read all of GoF's "design patterns", but I have read some of them clearly. So let's see if we can "Get together? J: Well, our program considers how to create objects. The creation mode should meet the requirements. Then let's look at the "intention" section of each model. Haha, the first one seems to have hit the color. Let's take a look at the abstract factory. "It provides an interface for creating a series of related or mutually dependent objects without specifying their specific classes ", at least "no need to specify their specific classes" meets our requirements. Let's take a look at its structure:
Our problems don't seem to be so complicated. Only orange, apple, and so on (should be the product). They are obviously one type, all of which are fruit, we only need a factory that produces fruit. The inheritance hierarchy on the left is not. There is only one FruitFactroy. Don't worry about it. It's just practical. J
The following things are clearly what we need:
Public interface IFruit { }Public class Orange: IFruit { Public Orange () { Console. WriteLine ("An orange is got! "); } } Public class Apple: IFruit { Public Apple () { Console. WriteLine ("An apple is got! "); } } |
What should we do with our FruitFactory? In the above structure diagram, it gives CreateProductA. Well, I will make orange, and there is a CreateProductB. Isn't MakeOrange enough ??
Public class FruitFactory { Public Orange MakeOrange () { Return new Orange (); } Public Apple MakeApple () { Return new Apple (); } } |
How can we use this factory? Let's write down the following code:
String FruitName = Console. ReadLine (); IFruit MyFruit = null; FruitFactory MyFruitFactory = new FruitFactory ();Switch (FruitName) { Case "Orange ": MyFruit = MyFruitFactory. MakeOrange (); Break; Case "Apple ": MyFruit = MyFruitFactory. MakeApple (); Break; Default: Break; } |
Compile and run the program, and enter what you want on the console. Immerse yourself in happiness.
But wait, it seems not perfect. If I want pear, I need to add judgment in the switch in the Customer Code and the MakePear method in the factory method. Better, only one method is provided in the factory, MakeFruit, and then a parameter Name is passed to represent the Name of the desired fruit. In this case, it seems that the switch in our customer code can be avoided. On the contrary, it seems that one is needed in FruitFactory. What are you waiting? .
FruitFactory: Public class FruitFactory { Public IFruit MakeFruit (string Name) { Switch (Name) { Case "Orange ": Return new Orange (); Case "Apple ": Return new Apple (); Default: Return null; } } } |
Customer Code:
String FruitName = Console. ReadLine (); IFruit MyFruit; FruitFactory MyFruitFactory = new FruitFactory (); MyFruit = MyFruitFactory. MakeFruit (FruitName ); |
This looks much better. At least I should not write a long string of judgment code in the Customer Code.
Ah Q is working again, and we are immersed in the joy of success. Well, the Code seems to be okay and there should be no improvement. However, another voice says:
"Except a little ......"
"Well? Wait, what ?"
"FruitFactory also has a switch. It looks like it's also ugly !"
"Hum, it must have been" refactoring "or" TDD ". How is the requirement so harsh! I am also idle. Can I change it ?"
Since there is no conditional judgment, only the fruit Name is passed in. For example, if Name = "Apple" is used to generate an Apple object, I need new Apple (). If I can: new MakeItToClass (Name) converts a string into a class. C # does not have the above syntax, but provides the corresponding mechanism, that is, reflection. An important class is the System. Type class, which plays a core role in reflection. We can use the method, field, attribute, and nested class of the Type object to find all information about the Type.
Another important class is System. Activator, which contains specific methods for creating object types locally or remotely, or obtaining references to existing remote objects.
We can first use the Type class to obtain the Type information of the class Name specified by Name, and then use Activator to create an object based on this information. What are you waiting?
Public class FruitFactory { Public IFruit MakeFruit (string Name) { IFruit MyFruit = null; Try { Type type = Type. GetType (Name, true ); MyFruit = (IFruit) Activator. CreateInstance (type ); } Catch (TypeLoadException e) Console. WriteLine ("I dont know this kind of fruit, exception caught-{0}", e. Message ); Return MyFruit; } } |
After such processing, when new fruits are added, we do not need to modify the customer code, and the factory Code does not need to be modified,