I. Introduction
???? 1. Introduction to the problem
???? Assuming that the program you designed has been deployed on the user's computer and can run normally. But one day, users have called - they demand new features. After determining the user's needs, you have found that the original software architecture is unable to win the need for new tasks - you need to redesign this app! But the problem is, even if you use a development cycle to complete the user needs, it is not guaranteed that the user's demand will change again. In other words, the possibility of demand spread still exists. Therefore, in this case, the plug-in architecture can more show its superiority.
???? 2. Comparison of several solutions
???? I summed up the plug-in architecture I have contacted, which can be roughly divided into the following categories:
I> script ???? Using a language to write the program logic of the plugin to a script code. This language can be Python, or other existing scripting languages that have been tested for a long time. Even, you can design a scripting language to cooperate with your program's special needs. Of course, use the most popular XML today. ???? This form of feature is that users who have a little programming knowledge can modify your script (^ _ ^ if you don't encrypt it). We can't argue this is the benefits or bad. Because the consequences of this situation are unpredictable. II> Dynamic Library DLL ???? The plugin function exists in the form of a dynamic library function. The main program enables the function signature in the plugin DLL through a certain channel (plugin writer or some tool), and then calls them in the right place. Readers who have used Matlab know that all features in matlab are almost all dynamic link functions. III> A polymeric ???? As the name suggests, it is to write the plugin function directly into EXE. In addition to completing your own responsibilities, the main program is also responsible for dispatching these "plugins". I don't like this form. This is difficult between the plug-in and the plugin, the main program and the plugin (mainly this) information exchange is much more difficult. The failure of Babylrenta [1] From a certain extent, information exchange cannot be achieved. IV> COM Components ???? COM [2] adds a bit of activity to this world. Only interface! Our plug-in needs to do just to implement the interface of the program definition. The main program does not need to know how the plugin implements a predetermined feature, which only needs to access the plugin through the interface and provide the interface of the main program related object. In this way, the information exchange between the main program and the plug-ins will become very simple. And, the plugin is completely transparent to the main program.
???? 3. Decision
???? C # is an object-oriented programming language. It provides an interface keyword to directly define an interface. At the same time, the System.Reflection namespace also provides a series of related objects to access the external assembly. This has made a solid foundation for our implementation of the plug-in architecture in C #.
???? Next, we will set up the implementation of this architecture in C # with a program editor with a plug-in architecture.
Second, the design process
???? Ok, now we are ready to put all the core code in the CSPLuginkerNel namespace. Create a C # class library project with VSIDE. Start our code in the namespace CSPLuginkernel.
???? 1. Interface design
???? Our program editor will open the document object being edited to the plugin. After the program is started, you enumerate each plugin and connect it to the main program while passing the interface of the main program object. The plugin can request a main program object or access the main program function through this interface.
???? According to the above needs, we first need a main program interface:
Public interface ketplicationObject {???? void Alert (String MSG); // Generate a message ???? void showinstatusbar (String MSG); // Display the specified information in the status bar ???? IDocumentObject QueryCurrentDocument (); / / Get the currently used document object ???? IDocumentObject [] queryDocuments (); // Get all document objects ???? // Set the event processor ???? void setdelegate (delegates whichone, eventhandler targer); } // Currently only this event public enum delegates {???? Delegate_ActiveDocumentChanged,} ???? then the IDocumentObject interface. The plugin accesses the editor object through this interface.
// // // Editor object must implement this interface // (Public interface IDocumentObject {???? // These attributes are the corresponding attribute mapping of the RichTextBox control ???? string selectionText {Get; set;} ?? ?? color selectionColor {get; set;} ???? font selectionFont {get; set;} ???? int class;} ???? int selectionLength {get; set;} ???? String selectionrtf {get; set;}? ???? Bool Haschanges {get;}? ???? void select (int start, int layth); ???? void appendtext (string str);??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Void savefile; ???? void savefile (); ???? void openfile (String filename); ???? void closefile ();
???? This interface does not need too much explanation. Here I only realize a few ways of the RichtextBox control, others may be obtained, readers can add themselves.
??? Then, according to the behavior of the plugin in its life cycle, the interface of the plugin is designed.
// // / / The plugin of this program must implement this interface /// (?) {???? connectionResult Connect (IapplicationObject App); ???? void OnDestory (); ???? void online (); ???? void run ();}? // /// indicate the result of the plugin and the main program /// public enum connectionResult {???? connection_success, ???? connection_failed}
???? The main program will first call the connect () method and pass the IapplicationObject to the plugin. The plugin does some initialization work in this process. Then, the onlOad () method of the plugin is called. After that, when the main program receives the signal (keyboard, mouse response), the plugin is called to start the plugin. At the end of the program, the onDestory () method is called. In this way, the life of the plugin is declared.
???? 2. Storage and acquisition of plugin information
???? One plugin needs to have its name, version and other information. As the designer, you must also leave your name and personal website to promote yourself. The new feature-attribute of C # is a good solution. So we define a class pluginfoarrtibute from System.attribute inherited:
// // Used to specify information about a plug-in /// public class pluginfoattribute: system.attribute {???? /// ???? /// DepRecated. Do not use. ???? / // ???? public pluginfoattribute () {} ???? public pluginfoattribute (???? ???? String name, string version, ???? ???? String Author, String WebPage, BOOL LoadwhenStart) {???? ????? // Detail is slightly going ????} ???? public string name {get {return _name;}} ???? public string version {get {return_version;} } ???? public string author;}} ???? public string webpage {get {return _WebPage;}} ???? public bool loadwhenstart {get {return_loadwhenstart;}} ???? /// ???? /// Used to store some useful information ???? /// ???? public object tag {???? ???? get {return _tag;} ???? ???? set {_tag = value;} ????} ???? /// ???? /// used to store the serial number ???? /// ???? public int index {? ?????? get {return _index;} ???? ???? set {_index = value;} ????}? ????????pring _name = ""; ???? private String_version = ""; ???? private String _author = ""; ???? private string _Webpage = ""; ???? private object _tag = null; ???? private int _index = 0; ???? // Will not use??? ? private bool _loadwhenstart = true;}
???? Use this class to modify your plugin and let him realize the IPLUGIN interface:
/// // my pluging 1 /// [???? pluginInfo (???? ???? "My pluging 1 (Just for test), ??????? ? "1.0", ???? ???? "jack h hansen", ???? ???? "http://blog.9cbs.net/matrix2003b", true)] public class myplugin1: iplugin { ???? public myplugin1 () {}? ???? #Region iPlugin member ???? // Detail is slightly ???? #ndregion ??????????private iDocumentObjectObject _Curdoc;} ???? 3. Loading plugin
???? Now you have to use the system.refelction namespace. The program searches for each file in the plugins directory at boot. For each file, if it is a plugin, load it with an Assembly object. Then enumerate each object in the program. Judging whether an assembly is a way to make our plug-in is to determine if it is directly or indirectly implemented from iplugin. Use the following function to pass the system.type of the object from the program set enumerated.
Private bool isvalidplugin (Type T) {???? bool return = false; ???? Type [] interfaces = t.GetInterface (); ???? foreaching {???? ?? ?? IF (theInterface.Fullname == "cspluginkernel.iplugin") {???? ???? ???? Ret = true; ???? ???? ???? Break; ???? ????} ????} ???? Return Ret;}
???? If the conditions are met, isvalidPlugin () will return True. Then the program creates this object and stores it in an ArrayList.
Plugins.add (Pluginassembly.createInstance (PlugingType.Fullname);
???? Now, you can write the test code.
Third, source code
???? Due to the limit, the complete source code (including test cases) is downloaded below. After downloading, please open it, regenerate the solution (requires .NET Framework 1.1). The test case is a plugin inserted into the red text in the RichTextBox control. Very simple, only test it.
Fourth, conclusion
???? That's all! With this plugin architecture, poor programmers do not have to spend the need for a demand. In addition, this paper is welcome to evaluate this article and the additional code herein. Also, that is, often go to my blog to see ~~ ^ _ ^
Note: [1] Babien Tower failure ??? "Moon Myth", Frederick P. Brooks Jr.? Chapter 7 Why Babien Tag failed [2] COM ??? For more technical details of COM / COM , please see "Mastering COM AND COM ", ASH Rofail, Yasser Shohoud.?