Использование «принципа единой ответственности» заставляет мои контейнеры иметь открытые сеттеры - PullRequest
8 голосов
/ 10 декабря 2010

Я стараюсь разрабатывать, следуя принципам SOLID.Я обнаружил, что когда вы используете «Принцип единой ответственности» (S SOLID), вам обычно приходится разделять классы между контейнерами данных и процессорами данных.Например, если у меня есть класс person с 5 свойствами, который читается из БД, вместо того чтобы помещать все в класс, я создаю класс Person со свойствами и другой класс PersonReader, который считывает эту информацию из базы данных и создает Person.

Если я сделаю это, я должен открыть свойства Person, чтобы PersonReader мог получить к ним доступ, но тогда у меня меньше инкапсуляции, чем поместить все в черный ящик и сделать свойства доступными только для чтения.

Я что-то упустил илиЯвляется ли это недостатком этого принципа?

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

РЕДАКТИРОВАТЬ: я изменил личность писателя на личность читателя, потому что не было необходимости публиковать установщики свойств в начале.

Ответы [ 4 ]

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

Может быть, я что-то упускаю, но почему бы вам не написать конструктор для класса Person, который принимает все его свойства?Таким образом, PersonReader сможет создавать человека, не открывая его свойства.

Другой вариант - пометить установщик свойств человека как внутренний (и сделать внутренние компоненты сборки видимыми для сборки PersonReader, если это в другой сборке).Это позволит вам получить доступ к свойствам пользователя, но не позволит никому изменять их вне сборки.

3 голосов
/ 10 декабря 2010

Большинство стратегий доступа к данным (методы ORM) предполагают компромиссы, которые вы описываете. Наименее навязчивые используют рефлексию (или самоанализ и т. Д.), Чтобы заполнить ваши сущности, когда это необходимо (например, когда нет открытых сеттеров).

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

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

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

В некоторых случаях может быть целесообразно создать интерфейс, через который можно записывать и читать внутреннее состояние.Таким образом, ваш персональный класс получит два мета: «сохранить» и «загрузить» (или «написать» и «прочитать», или что вы считаете подходящим).Этим методам передаются «IPropertyWriter» и «IPropertyReader» соответственно.(В моем случае я назвал их InStream и OutStream).

Person :: save (IPropertyWriter Writer) тогда будет делать

writer.writeProperty("name", this.name);
writer.writeProperty("age", this.age);

Вы можете утверждать, что вы все еще нарушаете Принцип единой ответственности, но я бы сказал, что никто другой не должен знать внутренности человека.(Особенно в моем случае с сериализацией мне пришлось хранить внутреннее состояние, которое частично не доступно через геттеры).Суть в том, что Person не связан ни с одним кодом базы данных.Ваш IPropertyWriter может быть чем угодно.Кроме того, ответственность за «знание своих собственных свойств» на самом деле не является новым свойством, а в любом случае присваивается каждому объекту.

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

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

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

Нет проблем с инкапсуляцией при открытии свойств Person, чтобы DatabaseReader мог получить к ним доступ, поскольку Person является избыточным, если ни один класс не может его создать.Это неотъемлемая часть ответственности любого класса быть творческим и разрушаемым.

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