Когда создавать класс против установки логического флага? - PullRequest
6 голосов
/ 16 декабря 2010

У меня есть интересный вопрос для постановки; когда следует создавать класс / объект модели, а не устанавливать логический флаг для данных, хранящихся в базе данных?

Например, скажем, у меня есть класс Person, который имеет логические флаги для President, Guard и PartTime. Этот класс / модель обрабатывается по-разному в зависимости от значения флагов. Таким образом, президент получает различные привилегии в системе от охраны и от части времени (r).

Когда можно использовать наследование одной таблицы для представления этой информации, а когда просто продолжать использовать логический флаг?

Мой инстинкт состоит в том, чтобы преобразовать их в различные Объекты, используя STI, так как это кажется мне более интересным. Проверка логических значений в некотором роде кажется неправильной, но я также могу найти место для этого.

Обновление для уточнения

Позвольте мне использовать другой пример, потому что в приведенном выше примере слишком много случаев.

Я работаю над приложением CMS, которое содержит страницы, страница может быть общедоступной, частной, общей, скрытой или по умолчанию (то есть это то, что вы получаете, когда вы не указываете страницу в URL). Прямо сейчас у нас есть модель Page, и все это логический флаг - Public, Default, Shared.

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

Я согласен с комментарием ниже, что пример «Роли для человека» имеет большой смысл. Я не уверен, что для примера страницы это так.

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

Примечание : контекстом вопроса является приложение Ruby on Rails, но оно применимо для любого объектно-ориентированного языка.

Ответы [ 4 ]

4 голосов
/ 16 декабря 2010

Прежде всего, давайте установим, для чего обычно используется наследование одной таблицы.Это способ объединить хранение и поведение нескольких вещей, которые похожи друг на друга.Придерживаясь CMS, примером может служить таблица с posts, которая может быть либо Comment, либо Article.Они имеют схожие данные и поведение, но в конечном итоге это разные вещи.Независимо от того, является ли комментарий комментарием, не является состоянием объекта , это идентичность.

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

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

В некоторых случаях вы можете сохранить три или более различных состояния, которые являются взаимоисключающими.Например, страница может быть либо частной, либо общедоступной, либо общей (я не знаю, так ли это - давайте представим, что это так).В этом случае логическое значение не поможет.Вы можете использовать несколько логических флагов, но, как вы правильно заметили, это очень запутанно.Самый простой способ - смоделировать это как перечисление .Или, когда вам этого не хватает (как в случае с Rails), просто используйте строковые значения со специальным значением и добавьте проверку, гарантирующую, что вы используете только одно из значений private, public или shared.

Иногда определенные комбинации различных переменных состояния являются недействительными .Например, страница может быть черновиком или утвержденным (отражается логическим столбцом approved);и это также либо public или private (также отражается логическим столбцом).Мы могли бы решить, что страница должна должна быть утверждена, прежде чем она будет обнародована.В этом случае мы объявляем одно из состояний недействительным.Это должно отражаться в проверке вашей модели .Важно понимать, что черновик , общедоступная страница не является принципиально невозможной, это невозможно только потому, что вы решаете, что этого не должно быть.

При создании модели тщательно различайте атрибуты, которые отражают фактические свойства и состояния субъектов в реальном мире, и бизнес-правила , которые определяют, что должно быть возможным, ичто не должно бытьПервый должен быть смоделирован как столбцы, второй - как проверки.


Исходный ответ:

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

С другой стороны, может быть Person, который является президентом , ведет себя иначе, чем обычный человек;и один человек может только быть президентом или охранником.В этом случае наследование может быть более подходящим.Я не думаю, что вы должны моделировать "неполный рабочий день" как подкласс, хотя.Это атрибут в любом случае.

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

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

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

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

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

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

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

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

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

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

В вашем случае эта эвристика будет означать, что у вас есть Person с атрибутом типа AccessRights, который решает, является лиопределенное действие может быть выполнено или нет.Человек либо дает доступ к этому объекту, либо делегирует соответствующие методы.После этого у вас есть PresidentialRights, GuardRights и PartTimeRights, реализующие этот интерфейс AccessRights, и вы готовы к работе.

Учитывая это, вам никогда не нужно менять класс person при появлении нового типа права доступа, вам может потребоватьсяизменить класс person, если появляется новый тип действия (зависит от того, делегируете ли вы и как делегируете), и для добавления новых типов AccessRights вы просто добавляете новые реализации AccessRights.

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

Я предпочитаю не использовать флаг для этого, но также не использовать для этого подкласс Person. Вместо этого прикрепите Роль (или, если у вас есть кто-то, кто является одновременно Президентом и Гвардией, набор Ролей) с подклассами Роли, управляющей привилегиями.

Лично я не являюсь ни президентом, ни гвардией, но я и программист, и музыкант, и иногда я выполняю несколько других ролей (на самом деле, я некоторое время был гвардией, будучи студентом много лет тому назад.).

Человек имеет роль.

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