20 октября 2007

Что лучше: Singleton или использование статических членов класса?

Наверняка ведь многие задавались вопросом: «Почему бы не использовать вместо Одиночки обычный класс со статическими методами и свойствами?». В ActionScript 3 создать Singleton без дополнительных маневров не получится и бывают случаи, когда хочется попросту обойтись без них.

На самом деле есть несколько причин, выступающих за то, чтобы использовать Одиночку:

  1. В ActionScript 3 статические методы и свойства не наследуются. Т. е. если вы реализовали какой-либо функционал в виде статических членов класса, то он не будет передан по наследству подклассам класса и вам придется заново определять этот функционал в каждом из подклассов.
  2. В дальнейшем ходе развития кода вашего приложения вы можете пересмотреть политику взаимодействия объектов в нем. И вам может понадобиться уже несколько экземпляров вашего класса, каждый из которых будет хранить собственные значения свойств, обладая при этом схожим с другими экземплярами функционалом. В случае использования Одиночки это делается без особого труда — достаточно переделать статический метод getInstance так, чтобы он каждый раз возвращал новый объект класса. Есть даже специальное название для паттерна, обладающего с Singleton схожей структурой, но позволяющего создавать несколько экземпляров классов и вести их учет — Multiton. В случае же использования класса со статическими членами это сделать уже довольно сложно: пришлось бы создавать полностью одинаковые классы-дубликаты нашего класса, что само по себе является просто ужасным примером дизайна приложения.
  3. Значения статическим членам класса будут присвоены во время инициализации самого класса. На практике это означает, что, как только дойдет очередь до инициализации класса, AVM или JVM присвоит статическим свойствам этого класса необходимые значения, и с этого момента они будут постоянно висеть в памяти, занимая и растрачивая попусту ресурсы компьютера. Это может быть особенно заметно, если класс хранит достаточно увесистые объекты типа изображений, звуков или видео. Кроме того потребуется больше времени и на запуск приложения. В отличие от этого варианта, вы можете разработать ваш Singleton таким образом, чтобы он поддерживал «ленивую» инициализацию. «Ленивой» называется создания экземпляра класса и присваивание значений его свойствам только тогда, когда это необходимо на самом деле, т.е. во время первого вызова getInstance.
  4. Использование объектов — более легкий вариант для понимания и отладки. Использование статических членов класса, которые не являются частью какого-то простого объекта, а принадлежат к самому классу, означает, что ваш код не создается в определенной точке вашего приложения. В результате этого могут возникать ошибки, которые довольно сложно выявить. Главным образом это проявляется, если ваш класс должен содержать ссылки на другие объекты, которые попросту еще не будут доступны во время инициализации свойств класса.

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

При создании классов утилит, т. е. классов представляющих собой библиотеки связанных друг с другом статических методов и статических полей, предназначенных для обработки простых значений или выполнения простых задач, не требующих взаимодействия с другими объектами. Примерами таких классов являются Math в ActionScript 3 или java.util.Arrays в Java. Создание экземпляров таких классов являлось бы абсурдным. Так же, маловероятно, что когда-нибудь потребуется наследоваться от этих классов. И, как правило, классы утилит не содержат большого количества полей и методов, чтобы это заметно сказывалось на времени запуска приложения. Поэтому в данном случае предпочтительнее использование класса со статическими членами вместо Одиночки.

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

Actionscript:
  1. package
  2. {
  3.     public class Foo
  4.     {
  5.         public function Foo()
  6.         {
  7.            throw new Error("You can't create instance of Foo. All its methods and properties are static");
  8.         }
  9.     }
  10. }

В ActionScript 2 или Java используйте простой приватный конструктор.

P.S.: Обязательно прочтите статью «Работа с сookies в as3 приложениях» от Алексея «Vooparker» Аникутина, в которой как раз и приводится пример небольшого, но очень полезного утилитного класса.

См. так же:

Теги:


10 комментариев к записи:

Юрий Яровой [ 20 октября , 2007 в 18:40 ]

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

__i [ 20 октября , 2007 в 17:53 ]

у тебя код не рабочий )), как же ты создашь экземпляр класса если ты вообще не можешь его создать без эксепшина?

непомню где и кто предлагал другой вариант

Actionscript:
  1. package
  2. {
  3.     public class Foo
  4.     {
  5.         public function Foo(blocker : Bloker)
  6.         {
  7.             //тут можно проверить если у нас уже инстанс нашего класса
  8.         }
  9.     }
  10. }
  11. class Bloker
  12. {}

я думаю схема понятна, Blocker виден только для нашего класса, естественно вызвать конструктор извне не удастся.

[...] и в отвлечение от этой темы - "Что лучше: Singleton или использование статических членов класса" от Garbage [...]

Vooparker [ 21 октября , 2007 в 11:11 ]

Что касается реализации Singleton на ActionScript я встречал 3 варианта. Первый, с блокирующим классом, что был приведен выше, предлагается в книге "Advanced ActionScript 3 with Design Patterns".
Второй вариант создает единственный экземпляр на этапе инициализации класса:

Actionscript:
  1. package
  2. {
  3.     public class Singleton
  4.     {
  5.         private static var __instance:Singleton = new Singleton();
  6.        
  7.         public static function get instance ():Singleton
  8.         {
  9.             return __instance;
  10.         }
  11.        
  12.         public function Singleton ()
  13.         {
  14.             if(__instance)
  15.                 throw new Error("You can not created instance directly");
  16.         }
  17.     }
  18. }

Однако этот вариант не обеспечивает "ленивой" инициализации.
И третий вариант - использование приватного флага, разрешающего инициализацию:

Actionscript:
  1. package
  2. {
  3.     public class Singleton
  4.     {
  5.         private static var __instance:Singleton;
  6.         private static var __allowInitialization:Boolean = false;
  7.  
  8.         public static function get instance():Singleton
  9.         {
  10.             if(!instance)
  11.             {
  12.                 __allowInitialization = true;
  13.                 __instance = new Singleton();
  14.                 __allowInitialization = false;
  15.             }
  16.             return __instance;
  17.         }
  18.        
  19.         public function Singleton()
  20.         {
  21.             if(!__allowInitialization)
  22.                 throw new Error("You can not created instance directly");
  23.         }
  24.     }
  25. }

Собственно выбор реализации Singleton можно ограничить первым и последним вариантами.

Junik [ 22 октября , 2007 в 11:45 ]

Имхо, еще более актуальна тема того, в каких случаях стоит использовать Singletone. Я много раз видела, как Singletone используют только как замену global.

Юрий Яровой [ 22 октября , 2007 в 23:16 ]

Юля, спасибо за дополнение. Я обязательно упомяну о мотивации использования Singleton в одной из следующих статей об этом паттерне.

Алексей [ 6 февраля , 2008 в 11:52 ]

Статья безусловно очень интересна. Но ведь книг уже достатчоно по шаблонам проектирования. Возможно ли опубликовать участки какого-то "боевого' кода?

Юрий Яровой [ 6 февраля , 2008 в 14:50 ]

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

Алексей [ 6 февраля , 2008 в 16:37 ]

Наверное это было бы чрезмерной наглостью с моей стороны :)
В блоге jvetrau.ru, автор описывает прошлый проект (не называя его имя), и решённые сложности.
Мне было бы очень интересно увидеть с какой задачей Вы столкнулись. Чтобы и я тоже смог понять, что без Sigleton'а тут не обойтись :)

Заранее большое спасибо!

[...] «Что лучше: Singleton или использование статических чле

Оставьте свой комментарий:

Имя: *
* — обязательно для заполнения
Электропочта: *
Сайт:
Сообщение *
Коментировать
Коментировать