2010-12-08 37 views
0

现在我已经使用适配器模式从调用代码中抽象我的WCF服务客户端,这样我就可以有效地单元测试业务对象而不依赖于服务客户端。例如:适配器模式与封装冲突吗?

public class MyBusinessObject 
{ 
    private ITheService _service; 

    public MyBusinessObject(ITheService service) { _service = service; } 

    public void DoSomethingOnTheServer() { _service.DoSomething(); } 
} 

现在适配器的接口和具体实现公开了与服务代理本身相同的合同。因此,继续例如:

public interface ITheService 
{ 
    void DoSomething(); 
    ServerObject GetData(); 
} 

public class DefaultService : ITheService 
{ 
    public void DoSomething() { ... } 
    public ServerObject GetData() 
    { 
     using (var proxy = new ActualServiceClient()) 
     { 
      return proxy.GetData(); 
     } 
    } 
} 

这工作得很好,很好,我能够有效地测试我的业务对象等

我的问题的事实,我从第二返回类型茎方法与服务强烈耦合。如果适配器返回了我要使用的类型的实例而不是来自服务的DTO /代理,那么它是否更有意义并且与Adapter模式更一致?

如果是这样,那么我很担心封装。在典型的用例中,调用服务来检索数据,然后将其填充到我的业务对象中。如果我想让只读属性暴露给我的UI,那么我不能将这些属性的赋值委托给另一个对象,比如适配器。

想法?

回答

1

给它更多思考和一些额外的阅读,我上面描述的方法更符合Bridge模式。这种认识帮助我看到了缺失的部分 - 适配器!就像Massimiliano说的那样,我现在有一个位于我的业务对象和服务之间的适配器。适配器负责将WCF服务公开的POCO/DTO/Entity/...公开到我的业务对象中。

而不是我的业务对象在其构造函数中引用服务(ITheService),它现在需要对服务适配器(ITheServiceAdapter)的引用。此接口的样子:

internal interface ITheServiceAdapter 
{ 
    void DoSomething(); 
    MyBusinessObject GetData(); 
} 

在具体实施(TheServiceAdapter),我使用AutoMapper来“适应”基于服务器的POCO/DTO返回由实际的服务到我的业务对象,如:

internal class TheServiceAdapter : ITheServiceAdapter 
{ 
    private ITheService _service; 

    public TheServiceAdapter(ITheService service) { _service = service; } 

    public void DoSomething() { ... } 

    public MyBusinessObject GetData() 
    { 
     var data = _service.GetData(); 

     return Mapper.Map<ServiceObject, MyBusinessObject>(data); 
    } 
} 

这工作很好,满足我从我的业务对象抽象服务实现的要求。唯一与WCF代理类型绑定的代码是适配器。另外,我仍然可以通过注入服务适配器的模拟实现来干净地单元测试我的业务对象。而且,因为我选择信任AutoMapper,所以我不需要单元测试适配器类,并通过集成测试来捕获代码中的任何问题。所以,一切都很好 - 对吧?

当然这还没有解决封装问题。幸运的是,Rockford Lhotka(CSLA的名气)在他的书中有关这个主题的很好的论文。我的解决方案是通过将所有这些代码放在一个单独的程序集中,并为setter提供内部作用域,使所有属性只读取消耗代码,从而“伪装”封装。这允许适配器设置属性,同时防止客户端代码执行相同的操作。

这并不完美,但它是一个解决方案。如果你有其他的想法似乎不是诡计,我很乐意听到它们!

0

服务应该永远不会返回只在“服务器端世界(WCF)上才有意义的对象”,它不仅仅是一个耦合事项 我可以建议您应该创建一个POCO对象,该对象将由WCF。 您可以根据需要创建此对象:在这种情况下,您只能添加将会公开给用户界面的只读属性。当然,您需要一个将您的复杂/服务器对象转换为POCO对象的对象。要实现此目的,您可以创建一个适配器用来构建POCO对象的类