A few days ago, I participated in a technical exchange between internal teams of the company, focusing mainly on IOC and AOP. In the spirit of learning and learning attitude and actively sharing, I will use a short story to analyze the "IOC past and present" in my eyes, so that beginners can learn and understand IOC more intuitively! It is also used as an example.
(Although the demand in the story is a little small, the visitor can try to enlarge it in his mind and think of it as a large application system)
I,IOCPrototype
1, Program V1.0
Speaking of this, UT has put forward a demand many years ago to provide a system with a function that can send an email to employees during the Spring Festival. We will send you a New Year's greetings in the email and inform you of the issuance of a certain amount of holiday fees.
After analysis, it was decided that Zhang San, Li Si, and Wang Wu were responsible for the system development.
Among them: Zhang San is responsible for the development of the logic control module logiccontroller.exe, Which is simplified to ut.logiccontroller.exe. Li Si is responsible for the greetmessageservice and integrates it with the UT component. messageservice. DLL; Wang Wu is responsible for the email function help class (emailhelper), and provides the UT component. email. DLL.
Class dependency:
The core code of the email function module is as follows:
public class EmailHelper{ public void Send(string message) { Console.Write("Frome email: " + message); }}
The core code of the Li Si message management module is as follows:
public class GreetMessageService{ EmailHelper greetTool; public GreetMessageService() { greetTool = new EmailHelper(); } public void Greet(string message) { greetTool.Send(message); }}
The core code of Michael Jacob's business integration module is as follows:
String message = "Happy New Year! 5000. "; messageservice. greetmessageservice service = new messageservice. greetmessageservice (); service. Greet (Message );
After a month of hard work, the three finally achieved success. The system also sent a letter of greetings during the Spring Festival. This kind of care brings warmth to employees, so it is well received by all employees!
After the Spring Festival, the corresponding functions have also been transplanted to applications similar to UT editorial department and UT real estate related to UT, and has been widely used in subsequent "Lantern Festival", "Dragon Boat Festival", "Mid-Autumn Festival" and other festivals.
2, Program V2.0
Another year is approaching ......
To be honest, the amount of the holiday fee may directly affect the itinerary of the entire holiday, thus affecting the overall quality of the holiday. Therefore, the department leaders attach great importance to it. The email notification method is often unable to be normally received in remote mountainous areas due to the impact of the network environment. Many colleagues outside the Chinese New Year are quite vocal about this. After being verified by multiple parties, we have to use the popular telephone language broadcast method for notification.
As a result, Zhang San, Li Si, and Wang Wu are busy again. However, Li Si has a headache because his module is not only used internally by UT, but also independently run in ut editorial department and UT real estate. You have to worry about how to minimize the impact of changes here. In order to achieve better results, Li Si decided to conduct rectification in the following ways.
①The initial design scheme is as follows:
First, in order to allow different "Blessing methods" to be effectively replaced, we decided to separate them using "interface-oriented" methods. At the same time, enable both the email notification class of emailhelper and the Voice broadcast class of telephonehelper to implement this interface. The core code is as follows:
public interface ISendable{ void Send(string message);}public class EmailHelper : ISendable{ public void Send(string message) { Console.Write("Frome email: " + message); }}public class TelephoneHelper : ISendable{ public void Send(string message) { Console.Write("Frome telephone: " + message); }}
In addition, to facilitate compatibility with new and old products, the controller is required to determine the current communication mode and transmit the parameters to the Message Management module. The core code is as follows:
public enum SendToolType{ Email, Telephone,}
[Note]: The above code is not an excellent design and will be removed from subsequent optimization schemes.
public class GreetMessageService{ ISendable greetTool; public GreetMessageService(SendToolType sendToolType) { if (sendToolType == SendToolType.Email) { greetTool = new UT.EmailV20.EmailHelper(); } else if (sendToolType == SendToolType.Telephone) { greetTool = new UT.TelephoneV20.TelephoneHelper(); } } public void Greet(string message) { greetTool.Send(message); }}
Finally, the business integration module makes appropriate adjustments based on specific business needs. The core code is as follows:
String message = "Happy New Year! Holiday fee: 5000. "; greetmessageservice service = new greetmessageservice (sendtool. Telephone); service. Greet (Message );
The future is coming soon, but the more difficult Li Si is, the more difficult it is to see, because considering the possibility of adding new blessing methods in the future, this future uncertainty, it will definitely make constant changes to the constructors in the existing enumeration sendtooltype and greetmessageservice of Li Si, which will be an endless task.
Besides, since John wants to pass sendtooltype to me, that is to say, in specific product applications, John's module must know how to bless him, so why not let him directly give me the instance of the blessing method instead of the simple type? In this way, I don't have to worry about it, so I optimized the design.
②, After the optimization design scheme:
Another bitter battle of the past month ......
Wang Wu's code is not affected.
Li Si deleted the sendtooltype enumeration and changed greetmessageservice as follows:
public class GreetMessageService{ ISendable greetTool; public GreetMessageService(ISendable sendtool) { greetTool = sendtool; } public void Greet(string message) { greetTool.Send(message); }}
Michael Zhang also changed the business logic control part to the following:
String message = "Happy New Year! 5000. "; isendable greettool = new telephonehelper (); greetmessageservice service = new greetmessageservice (greettool); service. Greet (Message );
Finally, Michael updated ut.logiccontroller.exe. messagesevice. DLL, Wang Wu provides a new component: ut. telephone. DLL, and integrate the interface into a UT. core. dll library. After multi-party integration testing, the system runs well!
[Comment ]:
Li Si successfully used "interface separation" and "Dependency inversion" to make the module initially meet the expansion requirements for the new blessing method. At the same time, because of the "dependency injection" method, the business logic control module of Li Si needs"Isendable"The instance is injected. In theory, the" IOC"The prototype of Reverse control.
ForThe advantage of Reverse control is that the modules in the red box are capable of coping with changes. When new blessing methods are added, ut. messageservice. dllThe component can be completely unchanged.
3, V2.1
Text Message notification methods have been put on the agenda because telephone language broadcasts must be answered, and subsequent queries are inconvenient.
Under this requirement, Wang Wu provides a new component: Ut. GSN. dll. The core code is as follows:
public class SMSHelper : ISendable{ public void Send(string message) { Console.WriteLine("Frome SMS: " + message); }}
James also changed the code to the following,
String message = "Happy New Year! 5000. "; isendable greettool = new smshelper (); greetmessageservice service = new greetmessageservice (greettool); service. Greet (Message );
Let's enjoy it!
4, V2.2
With the ever-changing ways of blessing, people's requirements are constantly evolving. The shortcomings such as too rigid text messages and insufficient information have not been revealed, which are favored by everyone.
In this case, Wang Wu provides the new component ut. WeChat. dll. The core code is as follows:
public class WechatHelper : ISendable{ public void Send(string message) { Console.WriteLine("Frome wechat: " + message); }}
James also changed the code to the following:
String message = "Happy New Year! 5000. "; isendable greettool = new wechathelper (); greetmessageservice service = new greetmessageservice (greettool); service. Greet (Message );
Let's get another chance !!
Ii. IOCExtension
1Li Si's Xiaoyao and Zhang San's focus
Because of the IOC inversion control concept, no matter how the system changes, the module in charge of Li Si is still quite stable in general. Therefore, Li Si's experience over the past few years can be described as carefree. However, in contrast, Michael Zhang has independent applications in UT, ut editorial department, ut real estate and other products, and their respective versions are different. Therefore, three versions must be maintained at the same time, it can be said that it is a bad fortune.
Of course, James once wanted to unify all versions to achieve unified code maintenance. For this reason, we have also communicated and coordinated with relevant supervisors. However, the UT editorial department and the telecommunications service provider have already cooperated with all text messages for free, so the text message method is the most popular; the ut real estate is considered as the best choice for email notification based on the particularity of the identity of the information recipient. Therefore, the dream of a Unified Version of James is ultimately fruitless.
Let's take a look at how Michael maintains the three systems at the same time. Their core code is basically as follows:
Ut Company (method)
String message = "Happy New Year! 5000. "; isendable greettool = new wechathelper (); greetmessageservice service = new greetmessageservice (greettool); service. Greet (Message );
Ut editorial department (SMS)
String message = "Happy New Year! 5000. "; isendable greettool = new smshelper (); greetmessageservice service = new greetmessageservice (greettool); service. Greet (Message );
Ut House (email)
String message = "Happy New Year! Holiday fee: 5000. "; isendable greettool = new emailhelper (); greetmessageservice service = new greetmessageservice (greettool); service. Greet (Message );
Over the years, in line with the serious and responsible work and customers, James has been exploring these "version maintenance", "product compatibility", and other dirty jobs for a long time ......
2Zhang San's way out
One day, Michael Jacob and Mr. Li made preparations to talk about wine ......
After three rounds of wine, Zhang San told Li Si that when your module got out of the "IOC inversion control", it reversed the "Change Point" to my module, let me generate a specific object and then inject it to you. It's easy for you, but I'm stuck in the quagmire ......
In the face of Zhang San's spof, Li Si can only carefully analyze Zhang San:
First of all, the messageservice message management module, as a dedicated message service, actually does not take the initiative to control the functionality of "whether to send messages by email or by blessing, the responsibility of this module is a little cool. Even if it turns together, it cannot be too sweet.
In addition, in line with the principle of single responsibility, this message service is not convenient to handle too many things, which should be handled by the business logic like "choosing a blessing method. Theoretically, logiccontroller, as the business integrator, is responsible for processing such businesses.
In addition, as a new demand, Wang Wu adds components (DLL) to this demand, which is essential. As a general business integration party, Zhang San is also difficult to get away from. Due to changes caused by new demands, it is also reasonable to have an impact on John and John. Even if step 4 is left blank, even if there is no "reverse control", John will face changes (like the sendtooltype parameter introduced in the initial V2.0 solution ), therefore, whether there is "reverse control" is always a change for James. Now, the "IOC inversion control" is adopted to achieve the stability of Li Si. For Michael Zhang, this is a "Profit-free" sales.
Finally, in terms of architecture design and development efficiency, although "IOC inversion control" reverts the change point from Lee's "messageservice" module to Michael's "logiccontroller" module, however, this is in line with the "solid object-oriented design" principle. It can be said that it is a good design, and it is understandable!
After hearing Li Si's discussion, Zhang San thought it was reasonable and the wine had to wake up! Since both of them have been fighting for many years in this industry, the debate is just a few minutes away. Immediately shift the focus of communication to the embarrassing situation of "how to solve the problem of maintaining three products at the same time.
After in-depth analysis, they felt that they had to solve the following two problems:
①: How can I effectively create an "isendable" instance to reduce the impact of new blessing methods on instance creation?
②: How can we reduce the impact of new blessing methods on the "logiccontroller" module to reduce maintenance costs?
[Remarks]
SolidThe five object-oriented design principles are very important to developers and can be seen everywhere in any large and medium-sized software project. We recommend that you master and flexibly apply them. The five originals are:
Single Resposibility Principle)
The principle of open closed Principle)
Lee's replacement principle (Liskov substitution principle)
Interface separation principle (Interface segregation principle)
Dependency inversion principle)
3, Solution
In order to realize the question of "how to effectively create an isendable instance", Michael introduced the "factory model". The changes caused by different blessing methods are encapsulated in an independent"Sendtoolfactory"Class, so that some code in this class can be changed later, without affecting all other places in the program that use isendable.
[Comment ]:
Implement isendable in factory Mode"Object instance creation is a typical design method of" high cohesion "and" loose coupling, it effectively makes the core part of the application do not care about the system's "Blessing", but the specific "Blessing" is created within the factory model. If requirements change in the future, you only need to make a few changes in the factory, and other code of the program will not be affected.
After successfully solving the first problem, we immediately raised the question of "how to effectively control the impact on the" logiccontroller "module after adding a blessing method. From the perspective of the current program structure, there are two major impacts after the new blessing method: first, change the code in the factory class to create a new instance, and then introduce a new dynamic library.
Finally, we decided to use the "factory mode + reflection mechanism" method to solve the above problems and rely on the node information of the configuration file in the factory mode, then, the "reflection mechanism" is used to dynamically create corresponding instances. In this way, even if a new blessing method is adopted, you only need to copy the dynamic library added by Wang Wu, then, you can change the node information in the configuration file. You no longer need to change the source code of any program or re-compile the program.
4Program V3.0
Create an instance in factory Mode
Public abstract class sendtoolfactory {public static isendable getinstance () {try {Assembly = assembly. loadFile (getassembly (); // load the Assembly object OBJ = assembly. createinstance (getobjecttype (); // create a class instance return OBJ as isendable;} catch {return NULL ;}} static string getassembly () {return path. combine (appdomain. currentdomain. basedirectory, configurationmanager. appsettings ["assemblystring"]);} static string getobjecttype () {return configurationmanager. appsettings ["typestring"] ;}}
Configuration File node Information
<?xml version="1.0" encoding="utf-8" ?><configuration> <appSettings> <!--<add key="AssemblyString" value="UT.EmailV20.dll" /> <add key="TypeString" value="UT.EmailV20.EmailHelper" />--> <!--<add key="AssemblyString" value="UT.SMSV21.dll" /> <add key="TypeString" value="UT.SMSV21.SMSHelper" />--> <add key="AssemblyString" value="UT.WechatV22.dll" /> <add key="TypeString" value="UT.WechatV22.WechatHelper" /> </appSettings> </configuration>
Since the launch of V3.0, the idea of IOC-Based Reverse control has been somewhat rewarding. Over the years, products have been running well, and even new "Blessing methods" have emerged, both Zhang and Li have no need to worry about it. At the same time, they can also be applied to different scenarios such as "ut Company", "ut editorial department", and "ut Real Estate.
【Comments]:
①: IOCOne of the common implementation methods of Reverse control is di.Dependency injection, which usually includes interface injection and setter injection.Injection and constructor injection. The Code provided in this example has the "interface injection" feature and is implemented through constructor.
②: IOCAnother method of Reverse control is dependency search. This method is generally used for type registration before use. If you are interested in this method, refer to Microsoft in the Microsoft enterprise database. practices. unity. DLLSource code in (https://entlib.codeplex.com/And detailed examples (for example, Enterprise Library 4.1 HOL)).
③:Dependency injection is generally performed by the caller (logiccontroller) Depends on IOCThe framework generates instance objects and then directly injects them into the called (greetmessageservice), The user directly uses this instance internally, and the code flow is clear.(Greetmessageservice)) Internal dependency IOCThe framework obtains the desired object instance and then uses this instance.
④: Both instances are generated to dynamically create instances, but the creation time is different. In my opinion, the logic control of dependency injection separation is relatively clear and hierarchical, but it is not as convenient and concise as it is to inject multiple objects.
Iii. IOCFramework
1, Mode Reuse
Since Michael Jacob successfully summed up the "IOC idea" in the above product development process, he has promoted and practiced other products in the future. In the process of use, James found that this mode can be effectively reused between modules and products, which not only greatly improves the development efficiency, it brings a lot of convenience for subsequent product expansion and maintenance.
2, Object container
Of course, in the practice of the "IOC idea", Zhang San also found that some areas need to be improved. For example, sometimes we may want to create a single object instance, but sometimes we want to create instances with multiple objects, or even a series of instances. Sometimes we want to create a local object instance, sometimes you need to create a remote service object instance .....
To cope with complex object applications, Michael Jacob upgraded a small workshop like "Object factory" to a powerful and intelligent "IOC object container ", this container can dynamically create and manage objects based on parameter settings or configuration files, so that the entire framework can manage object sets to a higher level.
3, IOCBasic Framework
Michael Jacob achieved the "Reverse Control" effect through the "interface separation" and "Dependency inversion" in the early stage, and combined with the effective "dependency injection" method, the system's "loose coupling" architecture is implemented, and the "factory mode + reflection mechanism" is used to effectively create objects dynamically and upgrade objects to "Object containers" in the future ", greatly reduce the impact of new requirements on the program. Through the above method, James successfully found a set of "basic IOC framework" with high reusability ".
4, IOCThoughts
Later, Michael Zhang put a wide range of practices on the "IOC Basic Framework" found in various products of the company, which was well received, and is integrated into a component set called "ut enterprise library" as a public component. Since then, in the circle of friends of James, IOC is widely used.
Several years later, we found that EJB, spring, struts, Asp. netmvc and other frameworks can see the shadows of IOC ideas. These frameworks have carried forward and extended the idea of John's initial IOC.
Now, IOC's ideas are shining brightly in software design and system architecture. However, I am very sorry that James, the mysterious Chinese population, does not know who it is.
4. Source Code
1Development Environment: vs2010 + net4.0 + ipvs7
2Download the sample source code (iocdemo), The code is very simple without writing comments.
IOC past and present