开发者

Does Adapter pattern conflict with encapsulation?

开发者 https://www.devze.com 2023-01-29 19:06 出处:网络
For quite a while now I\'ve utilized the Adapter pattern to abstract my WCF service clients from calling code so that I can effectively unit test my business objects without dependence on the service

For quite a while now I've utilized the Adapter pattern to abstract my WCF service clients from calling code so that I can effectively unit test my business objects without dependence on the service clients. For example:

public class MyBusinessObject
{
    private ITheService _service;

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

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

Right now the interface and concrete implementation of the adapter expose the same contract as the service proxy itself. So, continuing the example:

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();
        }
    }
}

This works well and good and I am able to effectively test my business objects, etc.

My problem stems from the fact that I am returning a type from the second method that is strongly-coupled to the se开发者_开发问答rvice. Wouldn't it make more sense and be more consistent with the Adapter pattern if the adapter returned an instance of the type I'm going to use rather than the DTO/proxy from the service?

If that is the case, then I am concerned about encapsulation. In a typical use case, the service is being called to retrieve data which is then populated into my business object. If I want to have read-only properties exposed to my UI, then I can't delegate assignment of these properties to another object, like the adapter.

Thoughts?


After giving it more thought and some additional reading, the approach I described above is more actually following the Bridge pattern. That realization helped me see the missing piece - the adapters! So much like Massimiliano was saying, I now have an adapter that sits between my business object and the service. The adapter is responsible for "adapting" the POCO/DTO/Entity/... exposed by the WCF service to/from my business objects.

Instead of my business object taking a reference to the service (ITheService) in its constructor, it now takes a reference to a service adapter (ITheServiceAdapter). This interface looks like:

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

In the concrete implementation (TheServiceAdapter), I use AutoMapper to "adapt" the server-based POCO/DTO returned by the actual service to my business object like:

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);
    }
}

This works great and satisfies my requirement to abstract the service implementation from my business objects. The only code that is tied to the WCF proxy types is the adapter. Plus, I can still unit test my business objects cleanly by injecting a mock implementation of the service adapter. And, because I choose to trust AutoMapper, I have no need to unit test the adapter classes and will catch any issues in that code through integration tests. So, all is good - right?

Of course this still didn't address the question of encapsulation. Fortunately, Rockford Lhotka (of CSLA fame) has a great dissertation on the subject in his book. My solution was to "fake" encapsulation by placing all of this code in a separate assembly and giving the setters internal scope for all properties that should appear read-only to consuming code. This allows the adapter to set the properties while preventing client code from doing the same.

It's not perfect, but it's a solution. If you have other ideas that don't seem to be as trick-ish, I'm open to hearing them!


A service should never return an object that makes sense only on the "server side world(WCF)" it is not just a coupling matter What I can suggest is you should create a POCO object that will be returned by the WCF. You can create this object as you want: in you case you can add only read-only property that will be exposed to the UI. Of course you need an object that converts your complex/server object into POCO object.To achieve this you may create a class that is used by the adapter to build-up the POCO objects

0

精彩评论

暂无评论...
验证码 换一张
取 消