长夜漫漫、无心睡眠!不断地在想,各大软件企业、各个开发团队、各种各样的项目都在根据自己的现实情况不断地在尝试各种各样的开发模式、思想、以及管理,但是每个团队中都会存在各种各样的难题,这样的现实也说明了,要做到一个IT企业的长远、合理、有效的规划是多么的艰难。所以各个团队就不断地学习各种管理技术各种先进的开发模式以适应瞬息万变的“挨踢”界,都向着同一个目标“在限定的时间内给客户提供高质量的软件产品”进发。前面有感而发,有点说大了,在接下来的一段时期里将跟大家一起探讨一个比较值得学习的开发思想,以及从这个开发思想延伸出来的能够用到实际项目中的一些有效的方法,探讨的内容就是从C\S结构插件式开发向B\S结构延伸。
插件式开发风靡各个软件项目已经许久,他的可靠性高、重用性高、耦合度小、低维护成本等都一直深受广大架构师以及程序员的喜爱,插件式开发也是从面向过程的编程转向面向对象编程的产物,插件式开发的著名产品可谓遍布全球,如:OFFICE、Visual Studio一系列产品、AUTODESK等知名产品都采用的该思想进行产品的研发以及规划,甚至更可怕的是AUTODESK如今的产品能够做到产品向上兼容,也就是低版本的程序能够兼容高版本的程序,虽然他们的内核我们不得而知,但是可以肯定的是这跟他们的产品的良好的规划分不开。在开源界也有很多著名的插件式开发的项目,其中最著名的就是SharpDevelop ,他是一个用于制作C#或者VB.NET的项目而设计的一个编辑器,同时,这个编辑器本身就是使用C#开发的,而且公开了全部源代码,因此这个工具本身也是学习C#以及软件开发规范的一个很好材料。通俗点讲,就是用C#和VB写了一个VS平台(包含解析器和编译器等所有模块,牛X),接下来我将用该项目一起去探寻插件式开发的奥秘。首先我们将了解一下什么是插件式开发。
插件式开发是什么?首先我们来先了解一些名词
插 件: 插件是可独立完成某个或一系列功能的模块。通常插件由宿主程序加载,不能独立运行。
宿主:宿主是承载插件运行的环境,为插件提供基本服务。通常插件由宿主程序管理和控制。(也就是框架)
插件式:通常是由开发人员编写宿主程序,并预先定义好系统提供基本服务接口和插件接口。然后由其他开发人员根据系统插件接口编写插件功能。通常插件以一个独立功能模块的形式出现, 对于宿主程序来说并不知道插件的具体功能, 通常宿主启动时检索插件信息,并根据预定的插件接口装载插件。
我想了解了这几个名词之后大概能知道插件式开发的工作原理。不错,就是宿主在启动时把所有的插件加载到框架中,根据插件的定义组成了一个整体。通俗点讲,就像一个房子(毛坯),刚开始很空,往里头放个空调它就能制冷、往里头拉盏灯它就能照明、往里头放个电脑就能进行电脑操作等,房子的组合根据需要而不同,有人把房子组合成了咖啡厅,有人把房子组成了快餐店,也有人把房子组合成了软件公司等。这些都是根据需求去研发出相应的产品,当然这个例子稍微有点不太靠谱,但是我想让大家更明白插件式的一些概念。再举个软件的例子吧,比如WORD中要加入打印功能,那么我们首先能想到的是可能是这几点:版面设计、打印机、网络,如果往细里想可能是:打印菜单、菜单名称、图片、右键菜单、快捷键等一系列的功能。那么这些功能都是WORD打印模块的一个插件,如果没有这个模块WORD框架一样能正常工作,只不过是缺失了打印功能,这个时候就可以发现,其实一个“插件”并不是一个简单的函数或者简单的功能,而是一些列功能的组合。所以如果要我们去做一个WORD的打印插件,那么我们就要定义菜单、图片、提取内容、版面设计、网络环境判断、打印机选择、以及相关的快捷功能。这个插件的功能做好之后提供一个插件接口给宿主(WORD)程序调用,在宿主启动的时候将会调用该插件进行解析以及装载,从而该插件的功能就插入到了宿主程序中,但是该插件的运行并不影响宿主的正常运行以及其他插件的运行。
这就是插件式的思想,说白了就是一些列的组合形成一个能够实现一系列功能目标整体,再强调一下该种开发思想的优点:高内聚、低耦合、重用性高、移植性强、稳定性高、可以进行混合编程等优点。呵呵,这些将是以后一段时间里我将陆续探讨与学习该思想的重点,因为这确实是我们每个项目中都迫切需要的一种理想状态。当然,不是每个项目都能够用上这种架构,但是了解并不会造成项目失败,一起探讨、共同成长!
忙碌的好多天过去了,自从上一贴发出后,不少同仁都对插件式开发提出了自己的看法以及分享一些插件式开发比较典型的例子,感谢李锋、肖明等 同仁的分享,也感谢所有顶贴的同志,今天来分享一下插件式开发著名的产品SharpDevelop。正如李锋所 说,SharpDevelop在.Net领域它的地位相当于Java领域Eclipse,他们的底层都有着一个灵活的插件体系框架,他们努力都方向都是各 种平台终有一天都是用同一个IDE。
SharpDevelop发展至今已经从1.1到现在的4.0,紧跟微软的步伐(如果我是盖茨,我会疯掉),我们在这里讨论的是2.2的框架,虽然有点落 后,但是大体的思想不变,新特性无法展现,有兴趣的朋友可以继续深入研究4.0的新特性。还没有搭建环境的朋友可点击下载, 对于SharpDevelop得部署,我写了一个简要的部署文档,可点 击下载,如果已经成功部署了该环境的朋友可不比下载。
完成了一系列的安装部署后,SharpDevelop的庐山真面目出现了,呵呵,第一次接触SharpDevelop的代码我也跟很多人一样,好庞大,但 是慢慢地围绕一个主题“插件式”,那么所面对的疑惑将会慢慢解开。
接下来介绍一下SharpDevelop中的一些比较亮点的功能,这些功能可能也是我们很多项目中需要的,在之后的篇幅中将会对这些功能进行更加深入的内 核级的分析和学习。运行SharpDevelop2.2点击【Tools】-【Addin Scout】既可以看到SharpDevelop的所有插件的全貌。
国际化支持(本地化):
一个能够在国际上通行的最基本的功能,能够让软件在国际通行上更有竞争力,SharpDevelop默认语言是英语,并且还能支持中文、日文、俄语、西班 牙语等语言,而且可以定制。
可能的用途:现在的软件产品光局限于国内用户明显已经不能够满足现在的需要,走向国际化那么 这个是一个必然的产物,而国际化恰恰就是这个国际化不可或缺的功能,从这个项目的研究中将能够更好地体会到国际化的一些实现流程以及一些实用的方式。
富文本编辑:
经常在使用Visual Studio平台的时候会想,他们的代码编辑器是如何实现的呢,答案就在SharpDevelop的TextEditor里头 (SharpDevelop\src\Libraries\ICSharpCode.TextEditor)。
可能的用途:项目在千变万化的需求面前,如果不能够满足用户的一些我们认为不合理的需求,有 可能会导致项目的延期甚至失败,除了能够满足用户的业务需求之外,很多用户往往从在界面上提出一些很稀奇古怪的需求,曾经在上海做的项目中,有用户提出的 需求是某个字母后面加“.”号,则这个字母以红色显示,后面加“'”则字母蓝色显示,效果就是这样:AAA.BB'C.DDD'。这种需求看起来简单但是其实有一套语法解析的功能,市面上也没有诸如此类能够自定义显示规则的第三 方控件。所以最后采取的策略是根据用户的需求后台进行解析然后通过GDI绘制输送到前台。这样的实现方式跟SharpDevelop的文本编辑器实现一致 所以SharpDevelop出来的代码显示效果如下:
public static float DrawDocumentWord(Graphics g,string word,PointF position, Font font, Color foreColor)
所以为了使用用户的需求,我想大家可能在界面上能够实现更好的人机交互,可以参考该功能。
命令式的操:
插件式开发中的所有插件可以说基本上都是命令式出发,而这些命令基本上都是在插件文件里定义好的,直接看实例:
<MenuItem id = "Open" label = "${res:XML.MainMenu.FileMenu.Open}" type="Menu">
<MenuItem id = "File"
label = "${res:XML.MainMenu.FileMenu.Open.File}"
icon = "Icons.16x16.OpenFileIcon"
shortcut = "Control|O"
class = "ICSharpCode.SharpDevelop.Commands.OpenFile"/>
<MenuItem id = "Project"
label = "${res:XML.MainMenu.FileMenu.Open.Project}"
icon = "Icons.16x16.OpenProjectIcon"
shortcut = "Control|Shift|O"
class = "ICSharpCode.SharpDevelop.Project.Commands.LoadSolution"/>
</MenuItem>
以上这一段就是打开菜单的一段插件定义,解释一下这些关键字的含义
label :显示的文字
type :菜单类型(如:按钮、COMBO框、悬停按钮等)
icon :显示的图标
shortcut :快捷键
class :对应的类
其中class就是该命令触发的地址,我们顺藤摸瓜找到了该命令如下:
public class LoadSolution : AbstractMenuCommand
{
public override void Run()
{
using (OpenFileDialog fdiag = new OpenFileDialog()) {
fdiag.AddExtension = true;
fdiag.Filter = ProjectService.GetAllProjectsFilter(this);
fdiag.Multiselect = false;
fdiag.CheckFileExists = true;
if (fdiag.ShowDialog(ICSharpCode.SharpDevelop.Gui.WorkbenchSingleton.MainForm) == DialogResult.OK) {
ProjectService.LoadSolutionOrProject(fdiag.FileName);
}
}
}
}
呵呵,看到这段代码我想大家应该明白配置文件跟UI以及后台处理的一系列的工作过程,这种命令式触发就完全合应了插件式开发的原理,每个插件都是独立的, 就是如果没有打开这个功能,那整个程序还是能够正常运转,只是缺失了该功能。
可能的用途:在 项目开发的过程中,我们往往碰到很多问题,其中我个人觉得最值得注意的,也是最浪费财力物力的因素,那就是代码重用性。那么插件式的开发思想能够很好地将 某个模块很好的封装起来,从而起到功能独立、即插即用、重用性高、维护方便等方面,现在网络上也流行很多插件式网站开发工具跟此种思想比较类似,比较明显 的就是比如一些电子商务网站:B2B、B2C、C2C的网站定制开发工具。那么延伸到项目开发过程中,如果能够长远规划项目的开发,确保同类项目尽量不做 重复的劳动,把都用到的功能、处理、算法等封装起来,那么类似的新项目就能够节省开发时间,节省下不少的开发成本,而且随着项目的增多,积累的代码财富就 越来越多,最后能够形成良性循环,各个项目都能够及时地交付高质量的软件产品。当然项目是千变万化的,需求是让人匪夷所思的,只能说尽可能地做到,要完全 做纯定制基本上是不可能的,有一点是可以肯定的,积少成多,聚沙成塔。呵呵。
不知不觉又深夜了。。。一晚上好像写不了多少东西,以后再多续几贴吧,总结一下,今天主要跟大家探讨的是SharpDevelop的一些基本的概念,以及 几个个人觉得比较值得学习的功能,当然简单的篇幅不能很全面地写出SharpDevelop里面包含优秀的架构和编程思想,在之后的帖子中将慢慢深入到SharpDevelop的内核去探寻更为让程序爱好者感到更为奇妙的思想以及技术。。。
睡了,晚安。。
未完待续。。。
下 一贴:SharpDevelop工程源代码解析以及插件实现的内核结构