Ну, а почему ты пишешь синглтоны? Если вы понимаете, что пошло не так при вашем синглтоните, вы знаете, на что следует обратить внимание в будущем.
Почему вы на секунду поверили, что синглтоны являются хорошим решением для любой проблемы? Потому что в книге так сказано? Не слепо доверяй книгам. Книги должны обосновывать свои требования, как и все остальные. Если я скажу вам, что ваш код выглядит намного лучше, если вы перевернете монитор вверх дном, бремя доказательств лежит на мне. Даже , если я какой-то бог кода. Даже если мне ежедневно поклоняются миллионы разработчиков по всему миру, мой совет все равно ничего не стоит, если я не могу оправдать это, и если я не могу заставить вас пойти "хорошо, это имеет смысл. Я понимаю почему вы рекомендуете это, а я не могу придумать лучшего способа сделать это ".
И то же самое относится к определенной книге шаблонов дизайна. Поэтому они написали, что «шаблоны проектирования потрясающие», и что «синглтон - это шаблон дизайна, и, следовательно, он тоже потрясающий». И что? Могут ли они обосновать это утверждение (нет, не могут, по крайней мере, в случае синглтона), поэтому проигнорируйте его.
Если кто-то еще предложил вам использовать синглтон, логика будет такой же: действительно ли эти люди представили хороший аргумент, почему это была хорошая идея?
И если вы сами пришли к оправданию, можете ли вы сегодня увидеть, что с ним не так? Что вы забыли принять во внимание?
Единственный способ избежать слишком большого количества ошибок в будущем - это учиться на ошибках, которые вы уже сделали. Как синглтоны или классы менеджеров ускользали от вашей защиты? На что вы должны были обращать внимание, когда впервые узнали о них? Или, если на то пошло, позже, когда вы свободно использовали их в своем коде. Какие были предупреждающие признаки того, что должен заставить вас задуматься: "Действительно ли эти одинокие звуки - правильный путь?" Как программист, вы должны доверять своему разуму. Вы должны верить, что вы будете принимать разумные решения. И единственный способ сделать это - учиться на плохих решениях, когда вы их принимаете. Потому что мы все делаем, слишком часто. Лучшее, что мы можем сделать, - это убедиться, что мы не будем принимать одни и те же плохие решения неоднократно .
Что касается классов менеджера, их проблема в том, что каждый класс должен нести только одну ответственность. Какова ответственность «менеджера класса»? Это .... эээ ... управляет вещами. Если вы не можете определить лаконичную зону ответственности, значит, класс неправильный. Что именно нужно управлять этими объектами? Что значит управлять ими 1026 *? Стандартная библиотека уже предоставляет контейнерные классы для хранения группы объектов.
Тогда вам понадобится немного кода с ответственностью за отрисовку всех объектов, хранящихся там. Но это не обязательно должен быть тот же объект, что и , хранит объекты.
Чем еще нужно управлять? Узнайте, что означает «управление» этими объектами, и тогда вы узнаете, какие классы вам нужны для управления. Скорее всего, это не единственная монолитная задача, а несколько разных видов обязанностей, которые следует разделить на разные классы.
Что касается синглетонов, я не буду повторять то, что говорил много раз раньше, так что вот ссылка .
Последний совет:
Винт ООП. В самом деле. Хороший код не является синонимом ООП. Иногда занятия являются хорошим инструментом для работы. Иногда они просто загромождают все и прячут простейшие фрагменты кода за бесконечными слоями абстракции.
Посмотрите на другие парадигмы. Если вы работаете в C ++, вам нужно знать об общем программировании. STL и Boost являются хорошими примерами того, как использовать универсальное программирование для написания кода для решения многих проблем, которые одновременно являются более чистыми, качественными и эффективными, чем эквивалентный код ООП.
И независимо от языка, из функционального программирования можно извлечь много ценных уроков.
И иногда простое старое процедурное программирование - это просто хороший и простой инструмент, который вам нужен.
Ключ к «хорошему дизайну» - это , а не для попытки «хорошего ОО-проектирования».Если вы сделаете это, вы заперетесь в этой единой парадигме.Вы могли бы также попытаться найти хороший способ построить дом, используя молоток.Я не говорю, что это невозможно, но есть гораздо лучшие способы построить гораздо лучшие дома, если вы также позволите себе использовать другие инструменты.
Что касается вашего редактирования:
С первым, D был ли правильный ответ?Должен ли я даже дать вид доступа к модели (это, вероятно, больше ответ MVC)?Выгодно ли представлению реализовать интерфейс (чтобы можно было подключить несколько разных представлений)?
DI был бы one вариантом для избежания одиночных переходов.Но не забывайте о старомодной низкотехнологичной опции: просто вручную передайте ссылку на объекты, которые должны знать о вашем «бывшем» синглтоне.
Ваш рендерер должен знать о списке игровых объектов,(Или это действительно так? Может быть, у него есть только один метод, которому нужно дать список объектов. Возможно, сам по себе класс рендерера в этом не нуждается). Поэтому конструктору рендерера должна быть дана ссылка на этот список.Это действительно все, что нужно сделать.Когда X требуется доступ к Y, вы передаете ему ссылку на Y в конструкторе параметра функции.Хорошая особенность этого подхода по сравнению с DI заключается в том, что вы делаете свои зависимости болезненно явными.Вы знаете , что средство визуализации знает о списке визуализируемых объектов, потому что вы можете видеть, как ссылка передается конструктору.И вам пришлось написать эту зависимость, что дало бы вам прекрасную возможность остановиться и спросить "это необходимо?"И у вас есть мотивация для устранения зависимостей: это означает, что нужно меньше печатать!
Многие из зависимостей, с которыми вы сталкиваетесь при использовании синглетонов или DI, не нужны.Оба эти инструмента позволяют легко и просто распространять зависимости между различными модулями, и это то, что вы делаете.И тогда вы получите дизайн, в котором ваш рендерер знает о вводе с клавиатуры, а обработчик ввода должен знать, как сохранить игру.
Другим возможным недостатком DI является простой вопрос технологии.Не все языки имеют хорошие библиотеки DI.Некоторые языки делают почти невозможным создание надежной и универсальной библиотеки DI.
Во втором случае, как еще можно было структурировать приложение?Является ли схватка просто использованием классов Manager в отличие от более конкретных имен?Или это то, что в некоторых случаях классы могут быть дополнительно разбиты (например, ObjectHolder, ObjectDrawer, ObjectUpdater)?
Я думаю, просто переименовать их - хорошее начало, да.Как я уже говорил выше, что значит «управлять» вашими объектами?Если я буду управлять этими объектами, что я буду делать?Три упомянутых вами класса звучат как хорошее разделение.Конечно, когда вы копаетесь в разработке этих классов, вы можете удивиться, почему вам даже нужно и ObjectHolder
.Разве это не то, что делают стандартные контейнеры библиотеки / классы коллекции?Вам нужен специальный класс для «удержания объектов», или вы можете просто отказаться от использования List<GameObject>
?
Так что я думаю, что оба ваших варианта действительно сводятся к одному и тому же.Если вы можете дать классу более конкретное имя, то вам, вероятно, не нужно разбивать его на несколько более мелких классов.Но если вы не можете придумать одно имя, которое дает понять, что должен делать класс, то, вероятно, его нужно разбить на несколько классов.
Представьте, что вы отложили свой код дляполгода.Когда вы вернетесь к этому, у вас будет любая идея, какова была цель класса "ObjectManager"?Возможно, нет, но у вас будет довольно хорошее представление о том, для чего предназначен «ObjectRenderer».Рендерит объекты.