Создание объектов без нарушения инкапсуляции - PullRequest
2 голосов
/ 03 апреля 2009

Я довольно новичок во всем этом, так что, вероятно, это ООП 101, но я не могу разобраться с этим, предположим, что следующий код C # живет в сборке:

internal interface IDataStore
{
    void Store(string name, object data);
    object Retrieve(string name);
}

internal class DBStore : IDataStore
{
    public DBStore(string connection) { }
    public void Store(string name, object data) { }
    public object Retrieve(string name) { }
}

public class GizmoManager
{
    public GizmoManager(IDataStore dataStore) { }
    // Other stuff
}

public class WidgetManager
{
    public WidgetManager(IDataStore dataStore) { }
    // Other stuff
}

Если вторая сборка пытается создать GizmoManager и WidgetManager, она не может этого сделать, потому что у нее нет способа завладеть DBStore (поскольку она внутренняя, а не публичная).

Следующие не работают AFAICS:

  • Сделайте DBStore и IDataStore общедоступными. Плохо, потому что клиентская сборка может затем обойти GizmoManager / WidgetManager и получить доступ к БД так, как ей нравится.
  • Не передавайте хранилище IDataStore конструкторам GizmoManager и WidgetManager. Плохо, потому что это снижает тестируемость (вы не можете легко передать в MockDataStore).
  • Сделай что-нибудь волшебное с фабриками. Кажется, ничего не решает, потому что вам нужно передать один и тот же IDataStore как в GizmoManager, так и в WidgetManager, и, таким образом, клиентской сборке все еще нужно назначить IDataStore для переменной (чего не может быть, потому что IDataStore является внутренним).

Это, наверное, потрясающе очевидно, но я просто не вижу этого. Как преодолеть это противоречие?

ТИА.

Ответы [ 5 ]

3 голосов
/ 03 апреля 2009

Просто сделайте интерфейс IDataStore общедоступным. Таким образом, клиенты могут создавать экземпляры ваших классов WidgetManager и GizmoManager с помощью фиктивных объектов, которые они создают сами.

Реализация шаблонов проектирования класса Factory , позволяющая создавать объекты GiszmoManager и WidgetManager с помощью клиентского кода. Таким образом, клиентский код никогда не сможет создать объект DBStore, поэтому он никогда не сможет обойти ваших менеджеров.

Кстати: Зачем суетиться с инкапсуляцией? Это может иметь смысл, если вы занимаетесь бизнесом проприетарных фреймворков, но в остальном YAGNI .

1 голос
/ 03 апреля 2009

Сделайте IDataStore и DBStore общедоступными, но сделайте конструктор DBStore внутренним. Затем сборка 1 полностью контролирует момент создания экземпляра DBStores, но сборка 2 может получить доступ и передать в DBStore.

Полагаю, вам понадобится фабрика в сборке 1, ограничивающая количество или конфигурацию создаваемых экземпляров DBStore.

0 голосов
/ 03 апреля 2009

Мне нравятся оба из них:

  • Не передавайте хранилище IDataStore в GizmoManager и WidgetManager. Конструкторы. Плохо, потому что это уменьшает тестируемость (вы не можете легко пройти в MockDataStore).
  • Сделай что-нибудь волшебное с фабриками. Кажется, ничего не решает, потому что вам нужно пройти тот же IDataStore для обоих GizmoManager и WidgetManager и при этом клиентская сборка еще необходимо назначить IDataStore для переменная (что не может быть, потому что IDataStore является внутренним).

Чтобы решить проблему тестируемости, но скрыть реализацию, общедоступный интерфейс должен предлагать только вариант: хранилища должны быть живыми, тестируемыми, предварительно подготовленными и т. Д. Таким образом, вы можете делегировать ответственность за правильную конструкцию IDataStore другой стороне, которая находится внутри сборки , Например. концепция фабрики, которая позволяет вам устанавливать только «тестирование», «развертывание», «отладка» и т. д. Имеют конструкторы по умолчанию (или синглтоны или что-то еще), которые внутренне обращаются к фабрике для правильного хранения с настройкой «mode».

0 голосов
/ 03 апреля 2009

Сделайте DBStore общедоступным, но сделайте всех участников, которых вы не хотите, показывать закрытыми или внутренними. Затем... Вариант 1. Удалите все элементы из IDataStore, которые вы не хотите, чтобы они были доступны вне сборки, и сделайте IDataStore общедоступным. Вариант 2. Переименуйте IDataStore в IDataStoreInternal и сделайте так, чтобы он наследовал от нового открытого интерфейса IDataStore, в котором нет участников (или только членов, которые вы хотите предоставить внешним образом).

0 голосов
/ 03 апреля 2009

Вы можете сделать интерфейс и классы public, но создайте методы для прямого доступа к базе данных internal. Таким образом, вы создаете экземпляр своего DBStore, не предоставляя доступа к методам, к которым другие сборки не разрешены.

internal методы видны только классам в одной сборке.

Я бы предпочел проверить, нет ли способа собрать ваши объекты без необходимости каждый раз создавать экземпляр DBStore. Возможно фабричный образец или внедрение зависимости? Затем вы можете сделать ваш интерфейс общедоступным, и позволить фабрике внутри первой сборки создавать их экземпляры. Это не влияет на тестируемость, но уменьшает количество создаваемых вами экземпляров объекта. Меньше new XYZ() заявлений лучше ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...