在基础篇中已经通过例子初步说明了如何基于CNF制作一个简单的资源管理器但很多开发人员并不理解树上的结点是如何得到的这就涉及到CNF的模型在详述CNF的模型之前需要先对Tree所使用的模型进行描述 对于早期习惯C/S开发的程序员来说对于SWT中的Tree并不陌生可以通过相应的TreeItem来创建子结点但是这并不是一种好的设计和使用方式它大大的增加了模型与UI之间的耦合度所以在Swing中使用了TreeNode来描述树模型而Eclipse则通过JFace提供了ITreeContentProvider接口来描述树模型这两种方式有异曲同工之处大家可以看一下这两个接口就会发现两者非常之雷同最大的区别在于前者通过userObject持有真实的数据而后者则是由TreeItem的getData来持有在使用的时候才会由相应的TreeViewer传给ITreeContentProvider从结构来说后者是一个纯粹的控制类而TreeNode则是更灵活一些可以作为一个控制类也可以作为一个模型体所以相对而言TreeNode更加灵活一些但从本质上而言两者并无区别 表面上看来一个TreeViewer将会拥有一个ITreeContentProvider用来取得树状的数据模型进而呈现出来但CNF中的树却更加灵活在基础篇中展现的图中却表示可以通过扩展点orgeclipseuinavigatornavigatorContent来添加新的结点而且这些与资源并没有本质的关系它可以与一个具体的文件或者目录资源绑定也可以与多个具体的文件或者目录绑定还可以是一个与文件或者目录无关的模型那么现在来看一下CNF到底做了哪些事情使得它的模型扩展如此容易呢? 首先启动Eclipse然后创建一个新的工作区再将CNF相关的代码以插件的形式导入到这个工作区中开始我们的分析过程 讲到这里要提到Eclipse提供的一个接口IWorkbenchAdapter和IWorkbenchAdapter这两个接口是有一点点怪的因为从设计的角度来看它将模型与展现层混合在一起违反常见的设计准则但从另一个角度来讲它可以减少用户扩展的内容有利于用户开发由此可见设计准则并不是一成不变的很多时候它也要在易用性和合理性方面做出适当的妥协这一点也可以在我们自己的设计中加以考虑设计并不是要偏向哪一个方向恰恰相反设计是要在多者之间如易用性稳定性合理性之间取得一个平衡点而不是在各方面都做到完美 另外ITreeContentProvider有一个方法getParent(Object parent)它是用来为一个指定结点找到相应的父亲结点从而便于查找和定位而这个方法却被很多人所忽视开发人员经常会习惯性的直接返回null而且也不会出现什么错误但这个方法其实却是一个非常有用的方法开发人员在使用Java资源管理器的时候有一个经常使用的功能就是LinkWithEditor这个功能经常是用来在资源管理器上定位当前打开的文件这个功能如此之重要以至于CNF专门为此定义了一个orgeclipseuinavigatorlinkHelper来支持该功能所以请根据实际情况来实现这个方法否则就无法正确的实现相应的功能 以上对TreeViewer的模型进行了简单的介绍和分析接下来就看一下CNF是如何处理树模型从而获得如此高的灵活性 CNF很好的利用了代理模式它自身并没有提供模型的能力所以它将提供模型的能力仍然交给外部扩展点提供的类它会根据当前要处理的结点以及每个扩展点的表达式来找出能够处理当前结点的ITreeContentProvider实例然后再将这些实例返回的子结点放入相应的Set中最终以数组的方式返回给TreeViewer从表面上来看可能很难理解正常情况下每个TreeViewer只有一个ITreeContentProvider的模型接口如何能够从多个实例中取得模型呢?就是由NavigatorContentServiceContentProvider这个代理类完成模型的组合功能 因此只要提供自己的ITreeContentProvidre实现然后通过扩展点挂入即可将各种真实或者虚拟的模型挂入系统 |