在 长期的工作过程中,经常需要包装第三方库提供的类.在多次这样做以后,发现要很好的包装一个第三方的库。需要包装两次。
第一层 提供辅助功能类(Helper 类 ).例如我在包装ArcEngine的 Workspace的时候就提供了一个DatabaseHelper类直接操作Workspace做我需要做的工作 。在这个层面上,代码的客户端是知道ArcEngine的Workspace的。而且在调用包装后代码的过程中还需要客户端提供Workspace本身.
第二层 提供封装类。在同一个项目中 我提供了另一个类DJWorkspace 用来完全封装Workspace.从打开Workspace的过程起开始封装,将日常所需要的功能都有这个类来提供。同时这个类的实现实际上上第一层的客户。当需要什么功能的时候直接调用,然后再处理。
在第二层由于不是完全封装,所以需要提供一个暴露底层Workspace的机会。另外,一定要有某种形式来告知DJApplication的客户:不要长时间保留底层Workspace的引用,最好每次使用都从DJApplication获取。这个是很重要的。
举例如下:
我们要获取一个Workspace中所有的FeatureClass的短名称 (没有用户名的那种)
在 DatabaseHelper中:
而在 DJWorkspace的实现者之一OracleWorkspace中有如下代码 :
我们在第二个类里面仅仅直接调用了Helper类的函数。
为什么要这样做呢?原因其实很简单:
1.我们的不同的DJWorkspace的实现者可能需要的GetFeatureDatasetNameCollection()方法其实实现是类似的。由于ArcEngine中的Workspace本身就是一个适应很广泛的接口。这样情况是存在的。
2.我们在写一些底层模块的时候可能会用到Helper类,而不是高层的包装类。高层的包装往往已经和业务有关系了。但是底层的模块确没有。这样底层的模块不可能为了使用第二层包装类里面的一个功能而导致自己依赖于它。这样做是不可取的。
所以将包装的过程分为两个层次是有必要的。在实际工作中也体现了它比一层包装要灵活得多。
第一层 提供辅助功能类(Helper 类 ).例如我在包装ArcEngine的 Workspace的时候就提供了一个DatabaseHelper类直接操作Workspace做我需要做的工作 。在这个层面上,代码的客户端是知道ArcEngine的Workspace的。而且在调用包装后代码的过程中还需要客户端提供Workspace本身.
第二层 提供封装类。在同一个项目中 我提供了另一个类DJWorkspace 用来完全封装Workspace.从打开Workspace的过程起开始封装,将日常所需要的功能都有这个类来提供。同时这个类的实现实际上上第一层的客户。当需要什么功能的时候直接调用,然后再处理。
在第二层由于不是完全封装,所以需要提供一个暴露底层Workspace的机会。另外,一定要有某种形式来告知DJApplication的客户:不要长时间保留底层Workspace的引用,最好每次使用都从DJApplication获取。这个是很重要的。
举例如下:
我们要获取一个Workspace中所有的FeatureClass的短名称 (没有用户名的那种)
在 DatabaseHelper中:
public
static
StringCollection QueryFeatureClassName(IWorkspace pWorkspace)
{
String ownerName="";
if(pWorkspace.Type==esriWorkspaceType.esriRemoteDatabaseWorkspace)
{
ownerName=pWorkspace.ConnectionProperties .GetProperty ("user").ToString ();
ownerName=ownerName.ToUpper ()+".";
}
StringCollection sc=new StringCollection ();
IEnumDatasetName edn=pWorkspace.get_DatasetNames (esriDatasetType.esriDTFeatureDataset);
IDatasetName dn=edn.Next ();
while(dn!=null)
{
string dsName=dn.Name.ToUpper ();
if(ownerName.Equals (LayerHelper.GetClassOwnerName(dsName)))
{
sc.Add (LayerHelper.GetClassShortName(dsName) );
}
dn=edn.Next ();
}
return sc;
}
{
String ownerName="";
if(pWorkspace.Type==esriWorkspaceType.esriRemoteDatabaseWorkspace)
{
ownerName=pWorkspace.ConnectionProperties .GetProperty ("user").ToString ();
ownerName=ownerName.ToUpper ()+".";
}
StringCollection sc=new StringCollection ();
IEnumDatasetName edn=pWorkspace.get_DatasetNames (esriDatasetType.esriDTFeatureDataset);
IDatasetName dn=edn.Next ();
while(dn!=null)
{
string dsName=dn.Name.ToUpper ();
if(ownerName.Equals (LayerHelper.GetClassOwnerName(dsName)))
{
sc.Add (LayerHelper.GetClassShortName(dsName) );
}
dn=edn.Next ();
}
return sc;
}
public
StringCollection GetFeatureDatasetNameCollection()
{
return DatabaseHelper.QueryFeatureClassName(this.SDEWorkspace);
}
{
return DatabaseHelper.QueryFeatureClassName(this.SDEWorkspace);
}
我们在第二个类里面仅仅直接调用了Helper类的函数。
为什么要这样做呢?原因其实很简单:
1.我们的不同的DJWorkspace的实现者可能需要的GetFeatureDatasetNameCollection()方法其实实现是类似的。由于ArcEngine中的Workspace本身就是一个适应很广泛的接口。这样情况是存在的。
2.我们在写一些底层模块的时候可能会用到Helper类,而不是高层的包装类。高层的包装往往已经和业务有关系了。但是底层的模块确没有。这样底层的模块不可能为了使用第二层包装类里面的一个功能而导致自己依赖于它。这样做是不可取的。
所以将包装的过程分为两个层次是有必要的。在实际工作中也体现了它比一层包装要灵活得多。