Какая польза от использования чистых моделей POCO?

15

В чем основное преимущество наличия чистых моделей POCO? Я понимаю, что Модели должны быть чистыми и простыми, но я склонен поддерживать содержание дочерних объектов в классах моделей. Например, если у меня есть ClassAи ClassBопределяется следующим образом:

public class ClassA
{
    public string MyProp { get; set; }
    public IEnumerable<ClassB> Children { get; }

    public void AddChild(ClassB newChild) { /*... */ }
    public void RemoveChild(ClassB child) { /* ... */ }
}

public class ClassB
{
    public string SomeProp { get; set; }
} 

Есть ли что-то не так с методами добавления и удаления? Должен ли я вместо этого просто выставить список и позволить клиентскому коду добавить все, что передает ответственность простых проверок данных, таких как not null, и не дублировать другой класс?

Любая помощь приветствуется. Спасибо.

Джесси
источник
Я бы удалил методы Add / Remove, если они не добавляют какое-либо значение, например, переводят нулевой аргумент ClassB в шаблонную версию объекта AddChild(ClassB newChild) => Children.Add(newChild ?? new NullClassB())
Грэм
Если вы когда-либо сталкивались с головной болью классов ActiveRecord с сотнями методов, которые могут или не могут быть тем, что вы хотите в любой момент времени, я думаю, что было бы легче понять апелляцию.
Кейси
Основная причина, по которой следует избегать этой конкретной конструкции, заключается в том, что она противоречит рекомендациям по разработке .net Это совершенно произвольно, но люди ожидают, что в коллекции будут методы мутации.
Фрэнк Хилман
@Casey Я не использую шаблон Active Record, метод add просто выполняет небольшую проверку данных. Существует метод удаления, потому что коллекция не раскрывается, они просто добавляются и удаляются из внутреннего списка. Однако я изменил его, чтобы использовать другой тип коллекции, который позволяет мне выполнять проверку, все еще используя встроенные методы Add / Remove.
Джесси

Ответы:

42

Ваши два вопроса не связаны.

Какая польза от использования чистых моделей POCO?

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

POCO - не более чем идея POJO. J был изменен на C, потому что люди смотрят на вас смешно, когда вы объясняете концепцию, в названии которой есть Java, если эти люди используют C #. Идея не зависит от языка. Они могли бы просто назвать это Простыми Старыми Объектами. Но кто хочет похвастаться использованием POO?

Я позволю Фаулеру объяснить происхождение:

Этот термин был придуман, когда Ребекка Парсонс, Джош МакКензи и я готовились к выступлению на конференции в сентябре 2000 года. В этой беседе мы говорили о многих преимуществах кодирования бизнес-логики в обычные объекты Java, а не с использованием Entity Beans. Мы задались вопросом, почему люди были против использования обычных объектов в своих системах, и пришли к выводу, что это потому, что простым объектам не хватает причудливого имени. Итак, мы дали им один, и это очень хорошо завоевало популярность.

martinfowler.com: POJO

Что касается вашего другого вопроса:

Есть ли что-то не так с методами добавления и удаления?

Я не люблю Aнапрямую знать о B. Но это DIP , а не POJO .

candied_orange
источник
У меня была прямая зависимость Bради простоты, в идеале они оба реализовали бы интерфейсы. Но Aсписок еще есть IInterfaceB. Что-то не так с AddChildметодом, если дочерние элементы слабо связаны через интерфейсные ссылки?
Джесси
6
Ради простоты я могу сделать целый ряд глупостей. Что мне не нравится, так это то, что A знает о B. A не использует B, поэтому нет необходимости определять надлежащий интерфейс, принадлежащий A, через который можно общаться с B. Насколько я могу сказать, это коллекция. Таким образом, A должен иметь дело с B через <T>, чтобы он ничего не знал об этом.
candied_orange
2
Я также видел «PODO» для «простого старого объекта данных», чтобы избежать какого-либо спецификатора языка в аббревиатуре. PODO звучит немного глупо (для меня это звучит как эпитет, который вы услышите на Татуине), скорее, чем POJO или POCO, я полагаю, но значительно менее глупо, чем POO.
KRyan
2
Интересно, насколько хорошо прошла бы презентация Фаулера, если бы он назвал их ПОО?
Оливер
3

С Add and Remove вы реализуете Collection<T>функции. Спросите себя, почему вы используете IEnumerable<T>вместо List<T>или какой-либо другой изменяемый класс? Очевидно, это не потому, что ваша коллекция должна быть только для чтения.

Единственная причина, по которой я могу думать, это то, что вы хотите контролировать, какие методы доступа вы хотите опубликовать. В этом случае было бы лучше создать свой собственный класс коллекции, инкапсулировать список, реализовать методы выбора Add и Remove и реализовать IEnumerable<T>. Затем используйте это вместо IEnumerable<T>типа вашей коллекции детей.

Но мне кажется, List<ClassB>что, вероятно, просто послужит вам хорошо.

Мартин Маат
источник
0

Что AddChildдобавляет и RemoveChildудаляет из? Если это из базы данных (или любого другого хранилища данных), у вас есть Active Record. Не обязательно всегда плохая вещь, но она определенно приближает вас к необходимости беспокоиться о каркасах, соглашениях, зависимостях и т. Д., Как упоминает @CandiedOrange.

В то же время, какой смысл избегать зависимости от ClassA до ClassB (или хотя бы InterfaceB), если все они находятся в одном приложении? В реальной области, которую моделирует ваше приложение, все зависит друг от друга. В реальном мире объекты делать есть коллекции других объектов , которые «принадлежат» к ним. Вполне уместно представлять эти отношения в вашем коде.

Единственная причина, по которой он становится немного сложнее, заключается в том, что вам нужно точно определить, как ClassB становится связанным с ClassA и отсоединяется от него. Таким образом, у вас есть немного поведения для реализации. Вы можете либо реализовать его внутри класса (который полностью «легален»; см. Https://stackoverflow.com/a/725365/44586 ), либо у вас может быть какой-то отдельный класс, который содержит такое поведение. Делайте то, что больше всего подходит для ваших индивидуальных обстоятельств.

В любом случае, POJO / POCO на самом деле просто ООП, как и предполагалось, без прикрас и необремененных. Следуйте принципам ООП, и вы будете в безопасности.

Джон М Гант
источник
На самом деле AddChild просто проверяет на дублирование, и null, и не позволяет ни того, ни другого. RemoveChild существует потому, что для предотвращения добавления бэкдора коллекция выставляется как IEnumerable. Это только выполнило бы стандартное удаление из коллекции все же.
Джесси
1
Спасибо за объяснение. Да, это звучит как тип поведения, который должен быть в POCO, и определенно лучше, чем просто выставление вашего базового IEnumerable для вызывающих абонентов для изменения или замены по желанию.
Джон М Гант
Я думаю, что Active Record - просто плохая модель.
Кейси
1
@ Кейси, ты не получишь от меня никаких аргументов по этому поводу. Но я бы не стал спорить, если бы кто-то тоже хотел этим воспользоваться. Главное, если бы Джесси намеревался использовать шаблон, подобный Active Record, который объединяет постоянство с определением модели, у него были бы все проблемы, выделенные CandiedOrange, и он не мог бы действительно претендовать на звание POCO. Но это не то, что он делает в любом случае.
Джон М Гант