Дизайн (практическое руководство) классов, содержащих наборы других классов

Как разработать классы, включающие наборы других классов?

Общий пример:

Рабочая область содержит количество Проектов.
Проект содержит большое количество Ресурсов.
Каждый Ресурс может содержать большое количество Файлов.

Таким образом, здесь определенными классами может быть Рабочая область, Проект, Ресурс и Файл. Рабочая область будет иметь список Проекта. Проект будет иметь список Ресурсов, и Ресурс будет иметь список Файлов. Конечно, каждый класс имеет свои связанные настройки.

Теперь основные вопросы:
a) Кто создает и добавляет класс к конкретному набору? Другой класс или класс, содержащий набор?
b) Также, как отслеживать конкретный набор и как сохранить то же?
c) Кто контролирует изменения в конкретном наборе?
d) Каковы различные шаблоны разработки, которые могли быть применены в таких ситуациях?

В основном я хочу уменьшить связь между различными классами.

Спасибо все

5
задан Amitd 25 June 2010 в 20:19
поделиться

3 ответа

Существует много видов взаимоотношений - рассмотрим

  • Автомобиль и колеса
  • Автомобиль и водитель
  • Автомобиль и зарегистрированный владелец
  • Клиент и строка заказа и заказа
  • Школа и класс и экземпляр класса

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

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

Относительно d). Есть один главный принцип Закон Деметры или принцип наименьшего знания.

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

После этого мы можем подумать о а). Творчество. Поскольку мы склонны использовать интерфейсы, часто имеет смысл использовать фабричные шаблоны. Остается вопрос, кто звонит на завод. Что мы предпочитаем:

   IPerson aPerson = myAutomobile.createDriver( /* params */);  

или

  IPerson aPerson = aPersonFactory.create( /* params */);
  myAutomobile.addDriver(aPerson);

Здесь, я думаю, довольно ясно, что автомобили мало что знают о людях, и поэтому второй вариант - лучшее разделение обязанностей. Однако, может быть, заказы могли бы разумно создавать OrderLines, а классы создавать ClassInstances?

б). Отслеживание? Вот почему у нас есть богатые наборы классов Collection.Какие из них использовать, зависит от характера отношений (один-один, один-много и т. Д.) И того, как мы их используем. Поэтому мы выбираем массивы, хэш-карты и т. Д. В соответствии с потребностями. Для автомобиля / колеса мы могли бы даже использовать атрибуты имен автомобилей - в конце концов, у автомобиля ровно шесть колес (frontLeft, frontRight, backLeft, backRight, запасное и рулевое управление). Если под «хранением» вы имеете в виду постоянство, то мы рассматриваем такие методы, как внешние ключи, в реляционной базе данных. Сопоставление между СУБД и объектами в памяти все чаще управляется хорошими механизмами сохранения, такими как JPA.

c). Аудит? Я не видел, чтобы одитинг применялся специально на уровне отношений. Очевидно, что метод automotive.addDriver () может быть сколь угодно сложным. Если есть бизнес-требование о проведении аудита этого действия, то совершенно очевидно, что это подходящее место для этого. Это просто стандартный вопрос объектно-ориентированного проектирования, связанный с тем, кому принадлежит информация. Общий принцип: «Не повторяйся» настолько ясно, что мы не хотим, чтобы каждый объект, вызывающий addDriver (), нуждался в аудите, следовательно, это работа Auto.

5
ответ дан 14 December 2019 в 04:30
поделиться

Создание хорошего объектно-ориентированного дизайна - это своего рода искусство , но следует помнить о некоторых принципах.

Подумайте, как пользователи будут использовать ваш интерфейс. Кто ваш пользователь? Это только вы и для определенной цели, или вы разрабатываете что-то для разных клиентов. Дизайн интерфейса сложен, но подумайте о реальных примерах того, как ваши пользователи действительно захотят использовать ваш интерфейс. Один из хороших способов сделать это - написать тесты, которые заставят вас использовать свои собственные материалы. Другой способ - посмотреть на существующие библиотеки, которые делают то же самое, и посмотреть, как они используются.

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

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

Хотя ты должен знать и использовать твою коллекцию библиотек. Знайте библиотеки коллекций любого языка / фреймворка, который вы используете, и используйте их. Кроме того, попробуйте сделать свои собственные интерфейсы совместимыми с этими библиотеками с точки зрения именования и поведения.

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

1
ответ дан 14 December 2019 в 04:30
поделиться

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

WorkSpace имеет тип Project + Project ^ 2 + Project ^ 3 ... (то есть все, что true из списка проектов, равно true рабочего пространства)

Аналогично,

Проект имеет тип Ресурс + Ресурс ^ 2 + Ресурс ^ 3 ...

Ресурс имеет тип Файл + Файл ^ 2 + Файл ^ 3 ...

Итак, в таком языке, как C # †, вы можете определить свой класс WorkSpace следующим образом:

public class WorkSpace : IList<Project> //the important thing here is that you're declaring that things that are true for a list of Projects is true for a WorkSpace. The WorkSpace class may in fact do other stuff too...
{

}

и аналогично для других классов.

Затем в своем клиентском коде вы должны использовать это следующим образом:

foreach (var project in WorkSpace)
{
    //do stuff
}

или

Projects.Add(new Resource() { file1, file2, file3, file4, /* etc */});

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

† Из вашей истории публикаций я предполагаю, что вы знакомы с C #, но это применимо к другим языкам.

2
ответ дан 14 December 2019 в 04:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: