插件程序开发
一、什么是插件程序?
插件是实现了某种软件接口的程序模块,第三方开发者可以遵循该接口开发独立的功能。插件模块通常以独立的文件形式存在,例如OCX文件等,也可能是一组文件的形式存在。
提起插件式,我们首先想到的是firefox,用过firefox的人都知道它是一个插件式程序。当一个功能需要,完全可以从网上下载一个插件后,重启后,就能使用。这个功能给我们带来许多的方便之处,这就是插件式程序的好处。
插件的本质在于不修改程序主体(平台)的情况下对软件功能进行拓展与加强,当插件的接口公开后,任何公司或个人都可以制作自己的插件来解决一些操作上的不便或增加新功能,也就是真正意义上实现“即插即用”软件开发。
平台+插件软件结构是将一个待开发的目标软件分为两部分,一部分为软件的主体或框架,可定义为平台,这是预先编译后的程序。另一部分为功能或补充模块,可定义为插件。这个就是后来要进行安装的插件程序。
假设你的程序已经部署在用户的计算机上,并且能够正常运行了。但是有一天,用户打来电话——他们需要增加新的功能。确定了用户的需求后,你竟然发现原有的软件架构已经无法胜任新增任务的需求——你需要重新设计这个应用了!但问题是,就算你又用了一个开发周期完成了用户需要的应用,切不能保证用户的需求不会再次变更。也就是说,需求蔓延的可能性依然存在。因此,这种情况下插件架构更能显示出它的优越性。
可以这么说,用它可以带来方便的地方,而且开发它,也很简单。而且这样的主程序根本就不需要改动。需要插件时,拿来就能用,插件更新时,也只需更新这个插件即可。
从程序开发这角度,一般是先开发主程序,决定哪些功能由主程序来完成,然后再建立接口,申明接口的内容,这些内容决定着插件功能的扩展,及方向的。这些都是有主程序开发者预先准备好的。插件开发者,从主程序开发者那里得到接口的内容,并书写继承这些接口的类,来完成具体的功能。
二、插件程序举例。
1、新建一个类库,并生成.dll(选择项目,点击“生成”,在该项目文件资源管理器的Debug中即可发现)。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IMsg { /// <summary> /// 这是插件必须实现的接口,也是主程序与插件通信的唯一接口 /// 换句话说,主程序只认识插件里的这些方法 /// </summary> public interface IMsgPlug { void OnShowDlg(); string OnShowInfo(); } }
2、再次新建一个类库,分别创建类MyConsole和MYDlg,同时添加对IMsg的引用,生成.dll。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using IMsg; namespace MYPlugin1 { public class MyConsole : IMsgPlug { #region IMsgPlug 成员 public void OnShowDlg() { Console.WriteLine("控制台调用插件的OnShowDlg方法"); } public string OnShowInfo() { return "myConsole"; } #endregion } }
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using IMsg; namespace MYPlugin1 { public class MYDlg : Form, IMsgPlug { #region IMsgPlug 成员 public void OnShowDlg() { this.Text = "插件子窗体"; this.ShowDialog();//调用Form的ShowDialog,显示窗体 } public string OnShowInfo() { return "MyDlg"; } #endregion } }
3、在解决方案资源管理器中添加窗体项目WindowsFormsApplication,修改Form1.cs为如下:
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { /// <summary> /// 存放插件的集合 /// </summary> private ArrayList plugins = new ArrayList(); public Form1() { InitializeComponent(); } /// <summary> /// 载入所有插件 /// </summary> private void LoadAllPlugs() { //获取插件目录(plugins)下所有文件 string[] files = Directory.GetFiles(Application.StartupPath + @"\Plugins"); foreach (string file in files) { if (file.ToUpper().EndsWith(".DLL")) { try { //载入dll Assembly ab = Assembly.LoadFrom(file); Type[] types = ab.GetTypes(); foreach (Type t in types) { //如果某些类实现了预定义的IMsg.IMsgPlug接口,则认为该类适配与主程序(是主程序的插件) if (t.GetInterface("IMsgPlug") != null) { plugins.Add(ab.CreateInstance(t.FullName)); listBox1.Items.Add(t.FullName); } } } catch (Exception ex) { MessageBox.Show(ex.Message); } } } } private void btnLoadPlug_Click_1(object sender, EventArgs e) { LoadAllPlugs(); MessageBox.Show("haha"); } private void btnExecute_Click_1(object sender, EventArgs e) { if (this.listBox1.SelectedIndex == -1) return; object selObj = this.plugins[this.listBox1.SelectedIndex]; Type t = selObj.GetType(); MethodInfo OnShowDlg = t.GetMethod("OnShowDlg"); MethodInfo OnShowInfo = t.GetMethod("OnShowInfo"); OnShowDlg.Invoke(selObj, null);//使用selObj调用OnShowDlg函数 object returnValue = OnShowInfo.Invoke(selObj, null); this.lblMsg.Text = returnValue.ToString(); } } }
4、将WindowsFormsApplication1设为启动项目,运行调试。
参考:http://www.cnblogs.com/sndnnlfhvk/archive/2011/06/02/2067713.html
C语言数据结构-创建链表的四种方法
结点类型:
typedef int datatype;
typedef struct NODE{
datatype data;
struct NODE *next;
}Node,*LinkList;
1、不带头结点的头插入法创建链表。
每创建一个结点,都使该结点成为头结点,这样头结点不断地向前移动,就可以创建一个没有特定头结点的链表。
首先创建的结点,会出现在整个链表的最末端,所以数据的写入是逆序的。
【开始的时候,head要初始化为NULL】
LinkList LinkListCreate(const int n) { int i; LinkList head; Node *p; head = NULL; for(;i<n;i++) { p = (Node*)malloc(sizeof(Node)); if(NULL == p) perror("ERROR"); scanf("%d",&p->data);
p->next = head; head = p; } }
开始时候,head 是一个空指针,创建一个结点p。现在head是指向一个链表的头结点,创建了一个新的结点p,向前插入。所以要p->next = head;然后再使head成为新链表的头结点。
2、不带头结点的未插入法创建链表。
创建这样的链表,首先指向头结点的指针不能移动,所以需要创建一个一直指向尾结点的指针rear。
LinkList LinkListCreate(const int n) { int n= 0; //创建一个一直指向头结点,一直指向尾结点的指针。 LinkList head; Node *p,*rear; rear = head = NULL; for(;i<n;i++) { p = (Node*)malloc(sizeof(Node)); scanf("%d",&p->data); if(NULL == head) //创建的第一个结点。 else rear->next = p;//链表非空 rear = p;//移动尾指针 }
rear->next = NULL;//最后将链表的结尾设置为NULL。 }
【值的注意的就是,最后设置链表的结尾为NULL】
3、创建带结点的头插入链表。
所谓的头结点是不存储数据的,他只是个指针结点。可以在该头结点存储一些这个链表的整体信息。比如链表的结点数量。
这种
创建方法跟第一种方法是一样的思路。
1 LinkList LinkListCreate(const int n) 2 { 3 int i = 0;LinkList p; 4 LinkList head = (Node*)malloc(sizeof(Node)); 5 head->next = NULL; 6 7 for(;i<n;i++) 8 { 9 p = (Node*)malloc(sizeof(Node)); 10 scanf("%d",&p->data); 11 p->next = head->next; 12 head->next = p; 13 } 14 15 return head; 16 }
【纯C语言,是要求所有的变量在使用的时候,必须在作用域的开始处定义。】
4、带头结点的尾插入法创建链表。
开始创建的时候,rear = head. rear->next = p; rear = p;最后要使的rear->next = NULL;
LinkList LinkListCreate(const int n) { int i = 0;Node *p,*rear; LinkList head = (Node*)malloc(sizeof(Node)); rear = head; for(;i<n;i++) { p = (Node*)malloc(sizeof(Node)); scanf("%d",&p->data); rear->next = p; //尾指针 指向新建结点 rear = p;//rear指针移动 } rear->next = NULL; return head; }
欢迎指正……