что такое синглтон unity

[Unity, лайфхак] Как сделать адекватный синглтон (singleton или уникальный для сцены) компонент

Что такое singleton – я надеюсь знают все.

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

В интернете достаточно много примеров по реализации синглтона на Unity. С ленивой инициализацией, с инициализацией в Awake или Reset, с кэшированием ссылок и т.д. и т.п. Приведу пример своего компонента:

Все это, конечно, прекрасно. И пока не сильно отличается от того, что можно найти на первой странице гугла по запросу «синглтон в юнити». Но я не увидел, чтобы авторы статей рассматривали 2 проблемы, с которыми столкнулся я:
1) При пересборке проекта (читай – при ЛЮБОМ изменении в любой части кода) коллекция _instances отчищается, т.к. класс UniqueComponentAtScene не является сериализуемым. А быть он таким не может, потому что нам заранее неизвестно, насколько сложные будут наследующие классы. Возможно их нельзя будет сделать сериализуемыми в принципе. И «ближайший» вызов метода Awake, где _instances заполняется, произойдет только в случае запуска проекта в редакторе.
Т.е. поведение компонента UniqueComponentAtScene – НЕ ОЖИДАЕМО, и заставляет каждый раз жмакать кнопку Play в редакторе. Можно забыть про это и словить внезапную ошибку NullReferenceException.
2) Если наследующий UniqueComponentAtScene класс1 будет иметь атрибут RequireComponent с указанием на класс2, который тоже является наследником UniqueComponentAtScene – то произойдет ошибка при добавлении дубля компонента класса1 на сцену.

Заключается ошибка в том, что после добавления Class1 на сцену, где уже есть Class1, движок подтянет Class2 – и добавит на GO. После этого для каждого из новых компонентов произойдет вызов Awake (т.к. синглтон то у нас ExecuteInEditMode), что должно удалить оба компонента. Ага, щаааззззз. Юнити говорит, что Class2 удалить нельзя, потому что Class1 ссылается на него. Хотя Class1 удаляет спокойно. И повлиять на это мы не можем, т.к. не управляем порядком вызова Awake для отдельных компонентов в сцене.

Ну и после такого долгого введения перейдем непосредственно к лайфхаку что такое синглтон unity. Смотреть фото что такое синглтон unity. Смотреть картинку что такое синглтон unity. Картинка про что такое синглтон unity. Фото что такое синглтон unityДля решения первой проблемы я использую такой хитрый атрибут, как DidReloadScripts. Упоминаний про него я нигде не встречал и вообще наткнулся совершенно случайно. Он позволяет пометить статичный метод, который будет вызван в редакторе после пересборки проекта или при первой загрузке редактора. После этого нам надо найти всех наследников UniqueComponentAtScene с помощью рефлексии и найти экземпляры этих классов на сцене. Когда все экземпляры, или компоненты, или синглтоны, найдены – вызываем для них Awake.
Правда здесь тоже есть нюанс – почему-то метод, расположенный в абстрактном генерик классе и помеченный атрибутом DidReloadScripts, вызывает ошибку «TypeLoadException: A type load exception has occurred». Толи баг, толи моих знаний языка не хватает для понимания… В общем, необходимо добавить прямо в файл с кодом UniqueComponentAtScene скриптуемый объект, в котором уже прописать нужный метод с атрибутом DidReloadScripts. Т.е. полный код файла UniqueComponentAtScene.cs будет выглядеть так:

Со второй проблемой способа борьбы я не придумал. Разве только словесно запретить использовать RequireComponent с указанием на наследников UniqueComponentAtScene что такое синглтон unity. Смотреть фото что такое синглтон unity. Смотреть картинку что такое синглтон unity. Картинка про что такое синглтон unity. Фото что такое синглтон unity
Если вы знаете, что делать со второй проблемой – с радостью выслушаю ваше решение. Ну и вообще замечания, предложения, пожелания приветствуются!

Источник

Паттерны. «Singleton», «Decorator». Unity

что такое синглтон unity. Смотреть фото что такое синглтон unity. Смотреть картинку что такое синглтон unity. Картинка про что такое синглтон unity. Фото что такое синглтон unity

Здравствуйте уважаемые читатели данной статьи. Сегодня я решил поговорить о ОО-проектировании в сфере геймдева, используя движок Unity. Сразу скажу, что данная статься является объективным видением использования паттернов и в особенности, их реализация. Кто-то может говорить о том, что в моих далее приведенных примерах лучше использовать тот или иной паттерн и возможно вы будете правы, но моя задача как минимум поверхностно пройтись по этой достаточно сложной теме. Я рассчитываю сделать небольшой цикл статей про разные паттерны и их примерное использование, чтобы архитектура вашего проекта стала гибкой и расширяемой.
Также хочу отметить, что данный цикл будет требовать определенных знаний в области ОО-программирования и базового ознакомления с понятием «паттерн».
Вроде всё оговорил, можем начинать!

Паттерн «Одиночка»

Данный паттерн предназначен для реализации единственного, уникального объекта во всей программе. При разработке игры вы можете столкнутся даже не один раз, когда вам нужно будет реализовать какой-либо модуль для игры (например систему сохранения игры или систему достижений). За продолжительное время в геймдеве я столкнулся с несколькими подходами к реализации уникальных объектов, но сегодня я хочу рассказать о том, на котором остановился на данный момент.
Былое: Ранее, я думал, что все подобные модули, которые я приводил в пример, должны быть уникальными объектами и делал каждый такой модуль на базе паттерна «Одиночка», но вскоре понял, что есть и более элегантный способ.
Собственно, я пришёл к выводу, что лучше всего сделать один единственный класс-одиночку, а внутри него хранить экзмепляры классов, которые могут быть задействованы из любой точки программы. Иначе говоря, у меня есть один класс на базе «Одиночка», который даёт доступ только для чтения всех ранее проинициализированных экземпляров классов.
Вот собственно его реализация:

Как вы можете видеть, класс-одиночка не сильно привязан к тем экземплярам, которые инициализируются за счёт оператора ‘??’, а также инициализирует он их на том же игровом объекте, на котором находится сам. Это значит, что если вам не обязательно добавлять все модули сразу. С другой стороны, если вы забудете добавить нужный модуль (модуль в моей интерпретации это управляющий класс), то движок вам напомнить не сможет.

Вот, собственно, и всё, данный подход можно использовать для вызова методов из разных модулей в любом классе.

Более подробнее ознакомится с паттерном можно будет здесь

Паттерн «Декоратор»

Далее, чтобы добавлять разные модные штучки на нашу мощную пушку, сделаем класс-обертку, которая будет являться классом-наследником для класса «Weapon» и назовём этот класс «WeaponWrapper». Вот как он выглядит:

Сделаем класс, который будет одним из модификаций для нашей пушки, пусть это будет глушитель. Класс будет называться «Muffler» и выглядеть так:

что такое синглтон unity. Смотреть фото что такое синглтон unity. Смотреть картинку что такое синглтон unity. Картинка про что такое синглтон unity. Фото что такое синглтон unity

Более подробно ознакомится с паттерном можно здесь

Источник

Singleton в Unity3D

Предисловие

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

Хочу предупредить, что человек я совершенно зелёный. Я не гуру программирования, не сеньор и возможно, что даже не middle. Адекватный опыт разработки имею исключительно в Unity, по сему затрагиваю только данную среду. Изначально было страшно делиться своими мыслями, но вспомнив, что порой тут публикуют серьёзные дяди, решил попытаться. Я люблю пользователей данного сайта, и даже если моя карма уйдёт в Марианскую впадину, то комментарии всегда помогут мне понять то, чего не смог понять ранее и найти ту самую истину!

За что же ненавидят паттерн Singleton

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

Давайте разберём некоторые из них!

Нарушение принципа единственной ответственности. Простите, что? По какой же причине наш Одиночка со 100% вероятностью нарушает этот принцип? То, что класс имеет глобальную точку доступа, не переносит его в разряд GOD-класса. SoundManager? NetworkManager? SceneManager? Даже в официальном уроке Unity3D SoundManager создан именно Singleton’ом. Видимо, данный пункт отпадает.

Singleton невозможно тестировать. Иными словами, аргумент людей заключается в том, что Одиночка сильно связан с объектом, изначально хранится в памяти и невозможно запустить тест, исключив его из работы приложения. Возможно, для людей не понимающих жизненного цикла класса MonoBehaviour всё так и будет. Но давайте поговорим на чистоту. То, что наш единственный instance создаётся в методе Awake(), не означает, что это обязательное условие для создания Singleton’а. Вы можете завернуть его инициализацию в любой другой метод и создать его только тогда, когда он вам впервые понадобится. Кроме того, люди почему-то говорят о том, что Singleton чудесным образом передаётся сквозь сцены. Для чего же тогда используется DontDestroyOnLoad? Загадка.

Тесная связь. Написав тысячи строк ужасно связанного кода, я как никто понимаю что такое страдать от багов, появляющихся в каком-то классе, при изменении другого. Но как вы считаете, является ли Singleton источником этой проблемы? Я — нет. Проектирование, и ещё раз проектирование. В одной из статей (простите, не смогу указать ссылку, ибо читал её невероятно давно) говорилось о том, что нужно уделять до 80% времени на проектирование структуры приложения, после чего дело пойдёт как по маслу. Я абсолютно согласен с этим.

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

Сегодня я посмотрел невероятно информативную презентацию об использовании Scriptable Objects. Она называется «Unite Austin 2017 — Game Architecture with Scriptable Objects». Материал будет полезен каждому Unity-разработчику. Выступающий приравнивал Singleton к стихийным бедствия, ядерной войне, говорил о том, что их студия старается создавать в играх prefab’ы, которые были бы самодостаточными и не имели тесных связей. Повторюсь, на мой взгляд — решение превосходное. Но что если наша игра требует связей?

Один из основных примеров использования Scriptable Objects — это игра Heart Stone, которая, как вы возможно знаете, частично сделана на Unity3D. Круто. Прекрасно. Восхитительно. Только беспокоит одно большое «НО». Создание карточек для Heart Stone может ограничиться табличкой в Excel, где мы забиваем имя карты, её описание, ману, атаку и конечно же хит-поинты. Готово. А вам потребовалось вот создать игру в которой всё завязано на генерации. Генерируется ландшафт, генерируются предметы, генерируются персонажи, генерируется даже то, что отвечает за генерацию. Паттерн одной из фабрик? Строитель? Ну, возможно. Наши сенсеи вряд ли станут врать. Минусами этих паттернов является загруженность лишним кодом и его общее усложнение. Я ни в коем случае не говорю о том, что нужно отказаться от использования любых паттернов кроме Singleton’а, я лишь хочу призвать людей не бояться Одиночек и не плодить паттерны там, где они не нужны, что может привести к неуместному усложнению архитектуры.

Немного дополнений

Зачастую мы можем видеть решения, которые выглядят совсем как «не синглтоны». Разработчики извращаются любыми методами. Делают public переменную для класса, перетаскивая в инспекторе единственный объект с нужным классом на другие сотни объектов, которым нужна эта ссылка. Вызывают в методе Start() GameObject.Find(). Зато не Singleton, здорово, правда? Связанность есть, Антипаттерна нет. Чудеса.

Основной проблемой Singleton’а среди начинающих разработчиков является то, что не нужно сильно задумываться о структуре. Из-за чего весь код обрастает Одиночками. Доступ к любому методу без ссылок, монолитность архитектуры. Всё это плохо, но каждый пишет код в меру своей грамотности. Будем честны. Программирование — это не просто вид деятельности, это полная смена образа мышления. Невозможно прочесть книгу на 700 страниц, сесть и сделать идеальную архитектуру. Всё приходит с опытом. И если ваш путь начался с монолитов — это совсем не повод отчаиваться. Понимание наличия проблемы — первый шаг к её решению!

Also, чрезмерное использование Singleton’ов абсолютно идентично чрезмерному использованию любого другого паттерна. Никто не даст вам печеньку за то, что вы сделаете абстрактную фабрику и 30 интерфейсов для класса, единственным назначением которого будет смена фонового изображения.

Семь раз отмерь, один раз отрежь!

Возможно, если комментарии будут очень насыщенными, я смогу дополнить эту статью или даже сделать 2 часть. Буду надеяться на критику моей писанины. Всем спасибо за внимание!

Источник

Использование Singleton в Unity3D

Вступление

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

В данной статье мы постарались не только описать такой подход к организации кода, как Singleton (в народе называемый паттерном проектирования), но и рассмотреть наиболее комфортные и правильные подходы к обработке событий и поговорить об удобности кода в целом.

Итак, в этой статье мы затронем следующие моменты:

Как работает Singleton

Прежде чем начать разбираться в схеме работы паттерна Singleton, необходимо понять что это. Singleton (Синглтон) — некий менеджер, через который производится управление игровыми скриптами. Как правило, синглтоны сохраняются от сцены к сцене без повторной реинициализации (наподобие глобального объекта).

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

Рассмотрим для примера организацию работы в мобильной игре:

В нашем случае Singleton — это объект переходящий от сцене к сцене, служащий для управления всеми объектами определенного типа в рамках игровой сцены (игры в целом).

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

Реализация Singleton в Unity3D

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

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

На примере выше мы создали основу для одного из игровых менеджеров (в нашем случае это менеджер Audio). Не обязательно проводить инициализацию через метод Start(). Вы также можете использовать для этого метод Awake(), чтобы ваш объект был готов еще до старта сцены.

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

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

На примере выше мы создали компонент, позволяющий нам автоматически включать/отключать AudioSource на объекте на основе статичных полей music и sounds в нашем менеджере.

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

Рассмотрим наш класс Boostrap-а:

Теперь мы можем использовать Boostrap и добавлять в него новые префабы менеджеров без необходимости их размещения на каждой сцене игры.

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

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

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

При успешном обращении мы получаем ответ следующего вида:

А при ошибке мы получаем ответ следующего вида:

Таким образом мы можем парсить ответ сервера при помощи JSON десериализации и нашей модели данных:

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

Пример простого контроллера игрока:

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

Рассмотрим данную строку:

Здесь мы видим, что идет сравнение индекса в цикле с идентификатором волос в модели данных игрока. Данная модель представлена в экземпляре объекта менеджера сети (NetworkManager), где был инициализирован объект для работы с авторизацией (auth), внутри которого размещены модели данных (player_data => profile_data => body).

Взаимодействие с Singleton

Для взаимодействия с менеджерами мы будем использовать либо экземпляр объекта (instance), либо прямое обращение для статических параметров.

Пример работы с instance:

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

Пример прямого взаимодействия со static-параметрами:

На примере выше мы обратились напрямую к статичному свойству sounds в менеджере AudioManager.

О плюсах и минусах Singleton

+ Нет необходимости постоянной настройки и описаний полей скриптов в инспекторе
+ К менеджерам можно обращаться через свойство instance
+ Удобный рефакторинг кода
+ Компактность кода

— Сильная зависимость кода
— Доступ только к скриптам-менеджерам в единственном экземпляре

Немного практических примеров

Использование делегатов
Мы можем сделать наш код более отзывчивым, добавив в менеджеры функции-делегаты. Таким образом для каждой функции может быть создан метод обратного вызова (callback).

Рассмотрим данный пример:

На простом примере выше мы создали метод, который вызываем функцию success, если параметр number был меньше 10 и функцию error, когда параметр был больше или равен 10 соответственно.

Использовать данный метод можно следующим способом:

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

Делегаты в связке с Coroutine в Singleton

Для наиболее удобного и правильного взаимодействия с сервером мы можем использовать связку Coroutine-функций и делегатов, тем самым получая возможность отправлять асинхронные запросы и обрабатывать ответ сервера. Ниже мы подготовили пример NetworkManager-а с использованием Coroutine-функций и делегатов.

Рассмотрим данный пример NetworkManager-а:

Теперь мы можем использовать это по назначению:

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

Заключение

Вообще, тема Singleton-ов и паттернов в целом в рамках проектов на Unity3D заслуживает отдельной книги и рассказать все в одной статье не получится. Ниже мы прикрепили несколько полезных материалов, где вы можете почитать об этом подробнее.

Источник

Singleton (Одиночка) или статический класс?

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

Что такое статический класс?

Что такое Singleton (Одиночка)?

Один из порождающих паттернов, впервые описанный «бандой четырех» (GoF). Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа. Мы не будем подробно рассматривать здесь этот паттерн, его предназначение и решаемые им задачи — в сети существует масса подробной информации о нем (например здесь и здесь). Отмечу лишь что синглтоны бывают потокобезопасные и нет, с простой и отложенной инициализацией.

А если нет разницы — зачем плодить больше?

Так в чем же все-таки разница между этими двумя сущностями и когда следует их использовать? Думаю что лучше всего это проиллюстрировать в следующей таблице:

SingletonStatic class
Количество точек доступаОдна (и только одна) точка доступа — статическое поле InstanceN (зависит от количества публичных членов класса и методов)
Наследование классов Возможно, но не всегда (об этом — ниже)Невозможно — статические классы не могут быть экземплярными, поскольку нельзя создавать экземпляры объекты статических классов
Наследование интерфейсовВозможно, безо всяких ограниченийНевозможно по той же причине, по которой невозможно наследование классов
Возможность передачи в качестве параметровВозможно, поскольку Singleton предоставляет реальный объектОтсутствует
Контроль времени жизни объектаВозможно — например, отложенная инициализация (или создание по требованию)Невозможно по той же причине, по которой невозможно наследование классов
Использование абстрактной фабрики для создания экземпляра классаВозможноНевозможно по причине осутствия самой возможности создания экземпляра
СериализацияВозможноНеприменима по причине отсутствия экземпляра

Рассмотрим подробнее перечисленные выше критерии.

Количество точек доступа

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

Singleton в «канонической» реализации:

Наследование классов

С наследованием статических классов все просто — оно просто не поддерживается на уровне языка. С Singleton все несколько сложнее. Для удобства использования многие разработчики чаще всего используют следующую реализацию паттерна:

А поскольку множественное наследование в C# и в любом CLI-совместимом языке запрещено — это означает что мы не сможем унаследовать класс Session от любого другого полезного класса. Выходом является делагирование синглтону управления доступом к экземпляру объекта:

Наследование интерфейсов

Использование интерфейсов позволяет достичь большей гибкости, увеличить количество повторно используемого кода, повысить тестируемость, и, самое главное — избежать сильной связности объектов. Статические классы не поддерживают наследования в принципе. Синглтон, напротив, наследование интерфейсов поддерживает в полной мере, поскольку это обычный класс. Но вот использовать эту возможность стоит только в том случае, если экземпляр синглтона планируется передавать в качестве входных параметров в смешанных сценариях или транслировать за границу домена. Пример смешанного сценария:

Возможность передачи в качестве параметров

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

Контроль времени жизни объекта

Время жизни статического класса ограничено временем жизни домена — если мы создали этот домен вручную, то мы косвенно управляем временем жизни всех его статических типов. Временем жизни синглтона мы можем управлять по нашему желанию. Яркий пример — отложенная инициализация:

Можно также добавить операцию удаления экземпляра синглтона:

Данная операция является крайне небезопасной, поскольку синглтон может хранить некоторое состояние и поэтому его пересоздание может иметь нежелательные последствия для его клиентов. Если все же необходимость в таком методе возникла (что скорее всего указывает на ошибки проектирования) то нужно постараться свести к минимуму возможное зло от его использования — например сделать его закрытым и вызывать внутри свойства Instance при определенных условиях:

Использование абстрактной фабрики для создания экземпляра класса

Статический класс не поддерживает данной возможности ввиду того, что нельзя создать экземпляр статического класса. В случае с синглтоном все выглядит просто:

Правда в варианте с аггрегацией синглтона придеться применить не совсем красивое и, немного громоздкое решение:

Сериализация

Сериализация применима только к экземплярам классов. Статический класс не может иметь экзмпляров поэтому сериализовать в данном случае нечего.

Так что же использовать Синглтон или Статический класс?

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *