Today, I will share with you the specific implementation details of the software architecture design ideas mentioned in ". Net brief introduction to the component system development model.
I read this article.ArticleAfter that, I always asked why I had to set up such a weird name "component" instead of "plug-in ". In fact, this name has been floating in my mind for a long time and I have never been able to find a suitable place to use it.
In a book, the component is explained as follows: The component is replaceable and consists of a series of small parts, which are also composed of smaller parts; the main reason why I want to distinguish between plug-ins and components is that these two names express different ideas. Plug-ins are plug-ins that can be inserted and unloaded. They do not emphasize the meaning of the infinitus Recursive Sub-plug-ins, So I separate them. Of course, you can also describe these two architectures in the same term, in fact, it is similar. The following describes how to use this design idea to develop a specific system.[Wang qingpei has all rights reserved. For more information, please sign it.]
I. Problem Analysis
Before development, we need to analyze the entire system. The core idea of the plug-in system is to adapt the developed system to daily requirements, it is easy to update features. But this is not the biggest benefit of the plug-in system. We can also achieve this advantage using the traditional three-tier, MVC development. It is nothing more than putting the DLL file under the Directory and then restarting it.
However, because the plug-in system has very detailed functions, most of the functions do not need to be updated unless necessary. The smaller the thing score, the better the control, but the development cost also increases with the control granularity. So we need to grasp this balance point. Not all projects are adapted to this architecture.
The plug-in system adopts interface-oriented development instead of class-oriented development. After the system requirements are met, function points need to be extracted for plug-in abstraction. In this case, the design capability of the architect of a project is tested. Poor design makes development impossible in the future. There are many such problems, such as unclear interface definitions, ambiguous return types, and full abstraction of the public part of interfaces, that is, whether the implementation of the base class is reasonable. These problems are complicated. When developing a large system, these problems cannot be sloppy, and the project fails. Extract the plug-in from the requirement, write the summary document, and write the desired document in detail. Design Documents may be useful in some major aspects, but weProgramMembers know that a design document cannot be generic, and not any system structure can be the same design document, which involves the company's document writing. If the design documents cannot cope with these complex system structures, architects can compile the architecture design documents of the Project. Only in this way can developers be clear at a glance, and programmers can take advantage of their autonomous power, in order to make the project work properly.
As we mentioned earlier, the plug-in system adopts the interface-oriented design and development, that is, the development idea promoted by the object-oriented field. Since we have an interface-oriented design, our plug-in is completely dependent on some interfaces, just like Com, and your interfaces remain unchanged, I can find you. The biggest benefit is that if my project needs to be implemented by a third party, we do not need to sign the Assembly file DLL, but cannot use the signature with another plug-in, in this way, the system is flexible. I like the development ideas of Masters and compare my projects to large robots. Any parts can be assembled and replaced. Do not make your project development so bloated and vulnerable.
The plug-in system also has high technical requirements for programmers. The plug-in system requires profound technical skills. They all say that this language is good, that language is good, as long as you are proficient in anything. At this time, it will test whether you have mastered the language. The language itself exists to meet certain requirements. JS is used to achieve interaction between htmldom, CSS is used to modify htmldom, and HTML is a structured representation language, in this way, the existence and use of a language have a direction. Do not compare the language with the language. Since the coupling of the plug-in is almost zero, we call the plug-in through interfaces. For example, I operate some functions in an interface, at the same time, these can be promptly fed back to another plug-in. Such a small function requires us to use a very complex call relationship. Any step-by-step processing that is not in place will cause trouble or even catastrophic changes in the future.
Ii. Real Project Analysis
I used this structure for system development. The preliminary conception was a headache, but the later stage was very good.
I have analyzed the basic theory in the article ". Net brief introduction of component system development mode", so I will not talk about it. Direct useCodeSee;
1. Main Program Implementation
When the main program wants to use a plug-in, we need to use a unified method or interface to obtain the plug-in corresponding to this module. Please refer to the Code:
/// <Summary>
/// Datasourceopen plug-in interface, context usage;
/// </Summary>
Basecome;
/// <Summary>
/// Open the sqlserver Data Source
/// </Summary>
Private void tools_sqlmenu_click (Object sender, eventargs E)
{
Basecome = newbasecome ();
(Basecome as performanceopen). passdataevent + = new passdatahandler (frmdbserver_passdataevent );
Basecome. startcome ();
}
Private void frmdbserver_passdataevent (list <string> param, Params string [] Par)
{
If (par. length> 0)
If (! Isopensource (par [0])
Bindtreeview (Param, par );
}
This is a menu Click Event of mine. This menu is a function menu in the main program. I need to call the corresponding plug-in the main program. The above basecome is the base class of the plug-in, all plug-ins share some features for easy calling and implementation. I used a newbasecome () method in the event. This method is a public method in the current form. Please refer to the Code:
/// <Summary>
// Obtain the component base class in a unified manner
/// </Summary>
/// <Returns> basecome object </returns>
Private basecome newbasecome ()
{
Return (plugmanager. plugkernelmanager. maineventprocess ("http://www.emed.cc/CodeBuilderStudio/Details/DataSourceOpen") as basecome );
}
I used this public method to obtain the plug-ins required for the current function, plugmanager. plugkernelmanager. maineventprocess () is a common method in the plug-in manager. This method gets the name of the plug-in configuration node in the configuration file based on the XML namespace you passed in. You may ask: "Why is the xml configuration file using this structure used? ". In fact, my personal habit is to use structured XML files, which is one of them. Second, I must determine the uniqueness of the plug-in configuration file. Because the plug-in system supports third-party implementation, I do not know what the plug-in name is, so I use the XML namespace to define. When I need it, I can get the current plug-in through the XML namespace. Let's take a look at the implementation of the plug-in manager. Please refer to the Code:
2. Plug-In Manager implementation
/// <Summary>
/// When an event occurs in the main program, you need to start the corresponding component
/// </Summary>
/// <Param name = "xmlnamespace"> namespace of the component </param>
/// <Returns> whether the component is loaded successfully. True: Successful; false: Failed </returns>
Public static object maineventprocess (string xmlnamespace)
{
Try
{
Plugdom dom = domcollection [xmlnamespace];
If (DOM = NULL)
Throw new system. Exception (
"The" + xmlnamespace + "namespace component cannot be found in the current context component set of the system. Check whether the loadconfig. xml component configuration file has been set accordingly ;");
Comeloadevent (DOM. Assembly); // The component is initialized successfully.
Return reflectiondomobject (DOM); // start the implementation component by reflecting the DLL file
}
Catch (exception ERR)
{
Comecommonmethod. logfunction. writeprivateprofilestring (
"Maineventprocess", Err. Source + "->" + err. targetsite, Err. Message, environment. currentdirectory + "\ plugmanagerlog. ini ");
Return NULL;
}
}
/// <Summary>
/// The main program has an event, releasing component resources
/// </Summary>
/// <Param name = "comeobject"> component object </param>
Public static void maindisposeprocess (Object comeobject)
{
Try
{
(Comeobject as main. interface. comebasemodule. basecome). Dispose ();
Comeexitevent (comeobject as main. interface. comebasemodule. basecome). comename );
}
Catch (exception ERR)
{
Comecommonmethod. logfunction. writeprivateprofilestring (
"Maindisposeprocess", Err. Source + "->" + err. targetsite, Err. Message, environment. currentdirectory + "\ plugmanagerlog. ini ");
}
}
Because there are many codes in the Manager, I only find the key code. In fact, the main task of the plug-in manager is to serve as a cohesion. In the main program, the plug-in object is obtained through the plug-in manager.
The plug-in Manager implements the following functions: when the system starts, it reads the plug-in configuration file and objects the configuration file, that is, it extracts XML nodes to form objects, which is convenient for us to use.
When a user needs a plug-in, we need to give the plug-in to the user in the form of a base class, which can eliminate the coupling between the plug-in Manager and interface. The plug-in manager is only applicable to the plug-in base classes. See the Code:
/// <Summary>
/// Internal method: dynamically loads the internal component object according to the assembly component host Assembly name
/// </Summary>
/// <Param name = "dom"> component Document Object Model plugdom </param>
Private Static object reflectiondomobject (plugdom DOM)
{
Try
{
Assembly ass = assembly. LoadFile (path. Combine (_ comeloadpath, Dom. Assembly ));
Type [] entrytype = ass. gettypes ();
Foreach (type in entrytype)
{
// All component base classes to find component entry points
If (type. basetype. fullname = "Main. interface. comebasemodule. basecome ")
{
Main. interface. comebasemodule. basecome =
System. activator. createinstance (type, type. fullname, _ comeloadpath, datetime. Now)
As main. interface. comebasemodule. basecome;
// Register an event
Notecomelifecycleprocess (basecome );
Return basecome;
}
}
Throw new exception ("to implement" + DOM. xmlnamespace + "identify component, check the component configuration file ");
}
Catch (exception ERR)
{
Comecommonmethod. logfunction. writeprivateprofilestring (
"Getdomobjectbyxmlns", Err. Source + "->" + err. targetsite, Err. Message, environment. currentdirectory + "\ plugmanagerlog. ini ");
Return NULL;
}
}
/// <Summary>
/// Record the lifecycle event data of all components
/// </Summary>
Private Static void notecomelifecycleprocess (main. interface. comebasemodule. basecome)
{
Basecome. comestartgoodsevent + = New Main. interface. comebasemodule. onstartgoodshandler (basecome_comestartgoodsevent );
Basecome. comeexitgoodsevent + = New Main. interface. comebasemodule. onexitgoodshandler (basecome_comeexitgoodsevent );
Basecome. comeexceptionevent + = New Main. interface. comebasemodule. onexceptionhandler (basecome_comeexceptionevent );
}
This is an important implementation code in the plug-in manager. Reflection and event registration are all here. Main. interface. comebasemodule. basecome is the plug-in base class. Because all plug-ins need to perform full lifecycle management, such as releasing some unmanaged resources and handles. Therefore, we need to perform unified management. Register the event here to facilitate listening. Let's take a look at the plug-in code that implements the interface:
3. Plug-in implementation
/*
* Author: Nanjing. Wang qingpei
* Coding time: 2011.5.28
* Copyright: Jiangsu Huacheng Network Information Technology Co., Ltd.
* Function: component implementation of data source development, performanceopen. Come Project;
*/
Using system;
Using system. Collections. Generic;
Using system. text;
Using main. interface. comebasemodule;
Namespace performanceopen. Come
{
/// <Summary>
/// Inherit the base class of the component. If the component is not fully implemented, the implementation will continue to be passed down;
/// </Summary>
[Main. interface. Attribute. whethernexttransfer (ifnexttransfer = true,
Childassembly = "codebuilderstudio. performanceopen. childe1 ",
Childinterface = "performanceopen. interface. nextcomeinterface")]
Public class controlcontent: basecome, Main. interface. performanceopen
{
This plug-in inherits the basecome object, that is, the plug-in base class. Then the main. interface. performanceopen interface is implemented, and this object can be obtained when the main program calls it.
Summary: The implementation of the plug-in system is almost complete. The package expansion interface, plug-in manager, and other knowledge are required. I hope you can provide a valuable role in Plug-in development.