Нужен совет по заводскому шаблону

Я работаю над тем, чтобы обдумать шаблон factory, используя его в простом проекте хранения данных в свободное время. Идея состоит в том, чтобы взять простые данные и сохранить их в базе данных, используя простой фабричный шаблон в VB.NET. Я думаю, что у меня есть базовое понимание самого шаблона, однако я борюсь с тем, как правильно вписать фабричные классы в архитектуру. У меня есть стандартная трехуровневая архитектура для этого проекта, которая выглядит примерно так:

Презентация

 -Presentation.Common
 -Presentation.DataStorageWebAppName

Бизнес

 -BusinessLayer.Common
 -BusinessLayer.DataStorageAppName

Данные

 -DataLayer.Common
 -DataLayer.DataStorageAppName

Общий

 -Common
 -Common.DataStorageAppName

Интерфейсы

 -Interfaces.Common
 -Interfaces.DataStorageAppName

Чтобы выделить конкретный сценарий, в котором у меня возникли проблемы с архитектурой приложения, позвольте мне привести пример. Предположим, что на бизнес-уровне я создаю класс в DLL BusinessLayer.DataStorageAppName с именем Foo. У него есть интерфейс IFoo, который находится в DLL Interfaces.DataStorageAppName. Чтобы создать экземпляр класса Foo через его интерфейс IFoo с использованием простого фабричного шаблона, прямо сейчас я создаю класс Factory в BusinessLayer.DataStorageAppName и пишу общий/статический метод, чтобы дать мне экземпляр через интерфейс IFoo. Позже, насколько я понимаю, я мог бы решить заменить объект, который возвращает этот класс Factory, без необходимости делать что-то еще (теоретически).

Чтобы добраться до сути, это работает, но что кажется странным, так это то, что теперь я вынужден создавать несколько классов Factory: по существу, по одному на каждую DLL, чтобы я мог избежать циклических ссылок. Есть ли более чистый способ реализовать эти фабричные классы, не прибегая к использованию стороннего решения, такого как замок Виндзор и т. д. и т. д. Кажется, что здесь мне не хватает фундаментальной концепции. Кажется, что должно быть возможно иметь один «репозиторий», если хотите, в архитектуре, которая отвечает за раздачу экземпляров объектов.

Заранее спасибо!


person Greg    schedule 29.12.2008    source источник
comment
Ваша главная цель - просто получить доступ к классам? Фасад или Фабрика?   -  person Perpetualcoder    schedule 30.12.2008


Ответы (3)


Я выбрал более простой подход. Я определил класс Entity, и у меня есть фабрика, которая создает список объектов (List‹ Entity >). Я сообщаю фабрике, какие типы я хочу вернуть, она предполагает, что типом является таблица, а свойствами являются столбцы, генерируется sql, получает данные, заполняет список новых экземпляров типа.

Фабрика также может получать объект Entity и использовать отражение для обновления его значений в базе данных.

Теперь единственное, что мне нужно сделать, это создать набор классов Entity для данной базы данных, которые, кстати, также являются объектами передачи данных.

person Otávio Décio    schedule 29.12.2008

Есть ли причина, по которой ваша реализация IFoo и фабричный метод, который ее возвращает, не могут находиться в сборке, отдельной от BusinessLayer (и, таким образом, вы можете ссылаться на эту новую сборку из всех клиентских сборок)? Если есть причина, возможно ли, что IFoo также должен быть определен в BusinessLayer (и, следовательно, не требует ссылок на сборку интерфейсов)?

Если ваш интерфейс действительно должен быть доступен не только с бизнес-уровня, а реализация действительно зависит от бизнес-уровня, вам нужно взглянуть на что-то большее, чем просто фабричный метод. Вы можете использовать некоторые из принципов Inversion of Control/Dependency Injection, чтобы лучше разделить проблемы.

[Редактировать в ответ на последующий ответ от OP] Фабричный метод, IMO, недостаточен, чтобы считаться подходом IoC. Лучше всего инкапсулировать конструкцию конкретной реализации для повторного использования в нескольких местах или просто для замести это под ковер. Чего мне не хватает, так это разрыва зависимостей: поскольку ваш фабричный метод живет в той же сборке, из которой он вызывается, чтобы изменить возвращаемый конкретный тип, вам нужно будет перекомпилировать. Рассмотрим разницу между следующими двумя:

public class FooConsumer1
{
    public void DoStuff()
    {
        IFoo myFoo = new Foo();
        myFoo.Bar();
    }
}

а также:

public class FooConsumer2
{
    public void DoStuff()
    {
        IFoo myFoo = FooFactory.getFoo();
        myFoo.Bar();
    }
}

public class FooFactory
{
    public static IFoo GetFoo()
    {
        return new Foo();
    }
}

Преимущество второго заключается в том, что если вы создаете IFoo более чем в одном месте, у вас есть только одно место для его изменения при создании класса SuperFoo для замены Foo. Кроме того, есть только одно место для размещения логики, если она каким-то образом будет динамически выбирать между двумя реализациями. Еще одно преимущество заключается в том, что если конструктор сложен/уродлив или требует некоторого дополнительного кода для поиска параметров конфигурации и т. д., то он скрывает все это от метода, который его использует.

Однако ни один из них на самом деле (по крайней мере, на мой взгляд) не поможет вам разорвать зависимости между этим методом и конкретной реализацией, которую он использует.

person Giraffe    schedule 30.12.2008

Не обязательно иметь несколько фабричных классов, если они решают разные задачи. Я бы посоветовал не использовать статические фабричные методы, а создавать экземпляры фабрик, которые вы используете. Тогда сами фабрики смогут реализовывать интерфейсы, и, возможно, часть причудливости исчезнет.

person Øyvind Skaar    schedule 31.12.2008