记住:只有表示层才能访问前面提到的对象,而且要让表示层尽量简单,简单到不需要测试,真正需要测试的代码(与业务逻辑有关)放在表示层以下。如此设计,您的表示层将非常简单,以至于不用测试(MVC框架中的View也能包含代码,但也没法测试,是一样的道理)。甚至,服务层还可以单独部署。
如果您的项目真的采用分层的设计,那么,就应该可以让界面与业务处理分离。比如您可以这样设计:
1. 表示层只处理输入输出的事情,它应该仅负责与用户的交互处理,建议这层代码简单到可以忽略测试。
2. 处理请求由UI层以下的逻辑层来完成,它负责请求的具体实现过程,它的方法参数来自于表示层。
为了检验您的分层设计是否符合这个原则,有个很简单的方法:
写个console小程序模拟UI层调用下层方法,能正常运行,就说明您的分层是正确的,否则,建议改进它们。
换一种方式使用ASP.NET框架
前面我提到HttpRequest有个InputStream属性, HttpResponse有一个OutputStream属性,它们对应的是输入输出流。直接使用它们,我们可以非常简单地提供一些服务功能,比如:我希望直接使用JSON格式来请求和应答。如果采用这种方案来设计,我们只需要定义好输入输出的数据结构,并使用这们来传输数据就好了。当然了,也有其它的方法能实现,但它们不是本文的主题,我也比较喜欢这种简单又直观地方式来解决某些问题。
2007年我做过一个短信的接口,人家就提供几个URL做为服务的地址,调用参数以及返回值就直接通过HTTP请求一起传递。
2009年做过一个项目是调用Experian Precise ID服务(Java写的),那个服务也直接使用HTTP协议,数据格式采用XML,输出输入的数据结构由他们定义的自定义类型。
2010年,我做过一个数据访问层服务,与C++的客户端通信,采用ASP.NET加JSON数据格式的方式。
基本上这三个项目都有一个共同点:直接使用HTTP协议,数据结构有着明确的定义格式,直接随HTTP一起传递。就这么简单,却非常有用,而且适用性很广,基本上什么语言都能很好地相互调用。
下面我以一个简单的示例演示这二个属性的强大之处。
在示例中,服务端要求数据的输入输出采用JSON格式,服务的功能是一个订单查询功能,输入输出的类型定义如下:
- // 查询订单的输入参数
- public sealed class QueryOrderCondition
- {
- public int? OrderId;
- public int? CustomerId;
- public DateTime StartDate;
- public DateTime EndDate;
- }
- // 查询订单的输出参数类型
- public sealed class Order
- {
- public int OrderID { get;set;}
- public int CustomerID { get;set;}
- public string CustomerName { get;set;}
- public DateTime OrderDate { get;set;}
- public double SumMoney { get;set;}
- public string Comment { get;set;}
- public bool Finished { get;set;}
- public List<OrderDetail>Detail { get;set;}
- }
- public sealed class OrderDetail
- {
- public int OrderID { get;set;}
- public int Quantity { get;set;}
- public int ProductID { get;set;}
- public string ProductName { get;set;}
- public string Unit { get;set;}
- public double UnitPrice { get;set;}
- }
服