Конфликтует ли шаблон адаптера с инкапсуляцией? - PullRequest
0 голосов
/ 08 декабря 2010

В течение достаточно долгого времени я использовал шаблон Adapter, чтобы абстрагировать своих клиентов службы 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();
        }
    }
}

Это работает хорошо и хорошо, и я могу эффективно тестировать свои бизнес-объекты и т. Д.

Моя проблема связана с тем, что я возвращаювведите из второго метода, который тесно связан с сервисом.Разве это не имеет больше смысла и будет более согласованным с шаблоном Adapter, если адаптер возвращает экземпляр типа, который я собираюсь использовать, а не DTO / прокси из службы?

Если этослучай, то я обеспокоен инкапсуляцией.В типичном случае использования служба вызывается для извлечения данных, которые затем вводятся в мой бизнес-объект.Если я хочу, чтобы свойства только для чтения отображались в моем пользовательском интерфейсе, я не могу делегировать назначение этих свойств другому объекту, например адаптеру.

Мысли?

Ответы [ 2 ]

1 голос
/ 11 декабря 2010

После долгих размышлений и дополнительного чтения подход, который я описал выше, более точно следует паттерну Моста.Эта реализация помогла мне увидеть недостающую часть - адаптеры!Как и говорил Массимилиано, у меня теперь есть адаптер, который находится между моим бизнес-объектом и сервисом.Адаптер отвечает за «адаптацию» POCO / DTO / Entity / ..., предоставляемой службой WCF, к / от моих бизнес-объектов.

Вместо того, чтобы мой бизнес-объект брал ссылку на службу (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, мне не нужно тестировать модули классов адаптера, и я буду выявлять любые проблемы в этом коде с помощью интеграционных тестов.Итак, все хорошо - верно?

Конечно, это еще не решило вопрос инкапсуляции.К счастью, Рокфорд Лхотка (из известности CSLA) имеет большую диссертацию на эту тему в своей книге.Мое решение состояло в том, чтобы «подделать» инкапсуляцию, поместив весь этот код в отдельную сборку и предоставив установщикам внутреннюю область действия для всех свойств, которые должны показываться только для чтения для потребляющего кода.Это позволяет адаптеру устанавливать свойства, не позволяя клиентскому коду делать то же самое.

Это не идеально, но это решение.Если у вас есть другие идеи, которые кажутся вам не совсем удачными, я готов их выслушать!

0 голосов
/ 09 декабря 2010

Служба никогда не должна возвращать объект, который имеет смысл только в «мире на стороне сервера (WCF)», это не просто вопрос связи Я могу предложить вам создать объект POCO, который будет возвращен WCF. Вы можете создать этот объект по своему усмотрению: в вашем случае вы можете добавить только свойство только для чтения, которое будет доступно пользовательскому интерфейсу. Конечно, вам нужен объект, который преобразует ваш комплексный / серверный объект в объект POCO. Для этого вы можете создать класс, который используется адаптером для создания объектов POCO

...