三、第一层的包装
用Web Service开发的技术优势不谈了,有关性能相对二进制调用较低的这个劣势也不提,从开发角度看Web Service的接口很类似COM的接口,它不可以被继承、也没有所谓的多态特性,因此如果把每个Web Service看成一个服务实体的话它是“平面”的,为了组织这些Web Service,需要首先对它们进行第一层包装,另外们称为某类OO语言可以使用的类,参考COM实现方式主要有两种——Contain和Aggregation:

图7:对Web Service进行第一层包装的方法 Contain(左)和Aggregation(右)
下面是两种包装方式的示例,为了看起来更直观,这里对SI的描述没有采用WSDL,而是采用代码的方式,假设有两个Web Service,分别提供如下功能:
C#
using System;
using System.Web.Services;
namespace VisionTask.Training.ServicePattern.UtilityService
...{
[WebService]
public class ServiceA : WebService
...{
[WebMethod]
public int GetQuantity() ...{ return 5; }
[WebMethod]
public int GetTotalCost() ...{ return 1000; }
}
}
C#
using System;
using System.Web.Services;
namespace VisionTask.Training.ServicePattern.UtilityService
...{
[WebService]
public class ServiceB : WebService
...{
[WebMethod]
public int GetAverage(int total, int quantity) ...{ return (int)(total / quantity); }
}
}
这时客户程序如果需要包括“GetAveragaeCost”、“ GetQuantity”、“ GetTotalCost”的功能,采用Aggregation则是直接在Directory上把ServiceA和ServiceB暴露给客户程序,由客户程序完成“GetAveragaeCost”的实现;采用Contain方式则是通过一个一个新的Service(例如:叫AdvancedService),由它完成“GetAveragaeCost”,Directory中仅仅对客户程序发布“ServiceA”和“AdvancedService”两个服务,将“ServiceB”作为内部服务隐藏起来。两种实现方式如下。
方式1:Aggregation
using System;
using VisionTask.Training.ServicePattern.UtilityService.CurrentServiceA;
using VisionTask.Training.ServicePattern.UtilityService.CurrentServiceB;
namespace VisionTask.Training.ServicePattern.UtilityService.Aggregation
{
public class Client
{
private ServiceA serviceA;
private ServiceB serviceB;
/// <summary>
/// 通过Directory 直接获得ServiceA 和ServiceB 的引用。
/// 由客户程序自己完成需要包装的功能——GetAverageCost。
/// </summary>
/// <returns></returns>
public int GetAverageCost()
{
if ((serviceA == null) || (serviceB == null)) throw new NullReferenceException();
return serviceB.GetAverage(serviceA.GetTotalCost(), serviceA.GetQuantity());
}
}
}
方式2:Contain
Web Service
using System;
using System.Web.Services;
using VisionTask.Training.ServicePattern.UtilityService.CurrentServiceA;
using VisionTask.Training.ServicePattern.UtilityService.CurrentServiceB;
namespace VisionTask.Training.ServicePattern.UtilityService.Contain
{
/// <summary>
/// 新包装的Service,完成客户程序需要的新功能——GetAverageCost。
/// </summary>
[WebService]
public class AdvancedService : WebService
{
[WebMethod]
public int GetAveragaeCost()
{
ServiceA a = new ServiceA();
return (new ServiceB()).GetAverage(a.GetTotalCost(), a.GetQuantity());
}
}
}
C#
using VisionTask.Training.ServicePattern.UtilityService.CurrentServiceA;
using VisionTask.Training.ServicePattern.UtilityService.CurrentAdvancedService;
namespace VisionTask.Training.ServicePattern.UtilityService.Contain
{
/// <summary>
/// 客户程序需要使用“GetQuantity”或“GetTotalCost”是调用ServiceA。
/// 如果需要使用包装的功能时,直接调用“AdvancedService”的“GetAveragaeCost”。
/// </summary>
public class Client
{
private ServiceA serviceA;
private AdvancedService advancedService;
}
}