Что мы должны использовать вместо класса «менеджер» в хорошем дизайне ООП? - PullRequest
35 голосов
/ 01 ноября 2010

У меня проблемы с разработкой игрового движка.Например:

Когда я думаю в Ресурсы , я думаю в ResourceManager класс для управления ресурсами на моем движке.

Этот класс получает несколько обязанностей :

  • Загрузка ресурсов.
  • Сопоставление ресурсов по идентификатору.
  • Убедитесь, что ресурсы загружаются только один раз.
  • Бесплатные неиспользуемые ресурсы (с использованием интеллектуальных указателей).

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

Некоторые люди объясняют, например, что ResourceManager следует разделить на более мелкие классы: A ResourceFactory , ResourceCollection , ResourceCache , a ResourceFacade ...

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

Мой вопрос: Есть ли учебник или документ с четким примером?Может кто-нибудь объяснить пример этой системы?Я благодарю вас, если вы можете написать небольшой пример на C ++ или другом подобном языке.

Заранее спасибо за вашу помощь!

Ответы [ 5 ]

15 голосов
/ 01 ноября 2010

Ты уже почти сказал это:

Этот класс получает несколько обязанностей

(оригинальный акцент).

Это нарушает Принцип единой ответственности . Кроме того, слово Manager указывает на объект, который управляет другими объектами, что противоречит объектно-ориентированному принципу, согласно которому объекты должны инкапсулировать как данные, так и поведение . Это быстро приводит к запаху Feature Envy code.

Делить менеджера на множество небольших классов - это правильно. Чтобы они были управляемыми, вы можете установить поверх них Facade .

12 голосов
/ 01 ноября 2010

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

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

Иногда я думаю, что шаблоны проектирования принесли столько же вреда, сколько и ясности миру разработки программного обеспечения!: -)

12 голосов
/ 01 ноября 2010

Может быть:

  • Загрузить ресурсы -> ResourceLoader
  • Отобразить ресурсы по идентификатору -> ResourceMapper
  • Убедитесь, что ресурсы загружаются только один раз-> CachedResourceLoader / этот использует ResourceLoader, когда он еще не загружен
  • Освободить неиспользуемые ресурсы (используя интеллектуальные указатели) ->?/ не уверен насчет этого, но load + unload выглядит как весьма сплоченные понятия

дополнительная информация в комментарии о "Свободных неиспользуемых ресурсах":

Во-первых, давайте проясним, что у нас есть только 2 из перечисленных выше: ResourceMapper и CachedResourceLoader.Поскольку экземпляр ResourceLoader используется из CachedResource, он не подвергается остальной части кода.

Обратите внимание, что следующее зависит от знаний домена, поэтому я буду держать его открытым, и вы будете знать, какой изэто имеет смысл / относится к частям, которые у вас есть.Я бы сказал, что здесь есть 3 варианта:

  • ResourceMapper использует CachedResourceLoader, и вы только открываете раннее остальную часть кода.
    • В этом подходе есть одна точка входа через ResourceMapper, поэтому имеет смысл контролировать FreeUnused ().
    • Как только он определит, что может освободить ресурс, он удалит его с карты.При необходимости он вызывает функцию Unload для определенных элементов в CachedResourceLoader
  • И CachedResourceLoader, и ResourceMapper используются вызывающей стороной.
    • Если вам нужен только FreeUnused из ResourceMapper, просто добавьте его туда.
    • Если его необходимо освободить от обоих, один из:
    • .FreeUnused в ResourceMapper получает cachedResourceLoader.После определения / удаления элементов из карты он передает список ресурсов для освобождения экземпляру cachedResourceLoader
    • .FreeUnused в ResourceMapper возвращает список ресурсов, освобожденных из карты.Вызывающая сторона вызывает .Unload для cachedResourceLoader, передавая список ресурсов для выгрузки.Возможно, у вас есть подходящее место в вызывающей стороне, и эти 2 вызова подойдут хорошо.
  • Вы используете ResourceManager, но вместо всех реализаций он использует ResourceMapper и CachedResourceLoader.,Это было бы очень тонко, просто делать вызовы другим, в частности вызовам .FreeUnused и .Unload в последнем подпункте выше.

Последнее замечание: Iдумаю, что это определенно стоит того, чтобы разделить обязанности и быть уверенным в этом.Тем не менее, я твердо придерживаюсь принципов SOLID, я не запоминаю имена шаблонов и не уделяю столько внимания правилам, как классы Manager, плохие.

8 голосов
/ 01 ноября 2010

Не думаю, что с вашим решением что-то не так.ИМХО, если вы думаете о том, что вы сказали с точки зрения Аспектно-ориентированного программирования , это просто аспект ваших ресурсов, который будет обрабатываться классом.

Хотя, если выВ общем, ваша кодовая база может развиваться в сотни строк, поэтому было бы лучше разбить ваши инфраструктурные функции ( Дизайн, управляемый доменом Шаблоны).

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

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

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

4 голосов
/ 02 ноября 2010

Я знаю все эти шаблоны проектирования (Фабрика, Коллекция, Фасад и т. Д.), Но на самом деле я не понимаю, как это можно объединить для создания (простой в управлении) системы управления ресурсами.

Кто сказал, что они должны быть объединены? Тогда ты вернулся туда, откуда начал, не так ли? Весь смысл в разделении классов менеджера состоит в том, что вы получаете несколько простых компонентов. Если вам нужна функциональность кэширования, вы говорите с кешем. Если вам нужна функция загрузки ресурсов, обратитесь к загрузчику ресурсов.

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