06.12.2011 21:57
Singleton'y we Flash'u [podstawowy]
Dzisiaj postanowiłem napisać parę słów singleton'ach czyli obiektach które mają tylko jedną instancję - czym są, jak je tworzyć we Flash'u i do czego służą.
Singleton to jeden z wielu wzorców projektowych i tak jak większość z nich może wydawać się nie potrzebnym komplikowaniem spraw które można rozwiązać w o wiele łatwiejszy sposób, jednak prawda jest taka, że w zamian zyskujemy przejrzystszy i bardziej wyspecjalizowany kod co jest szczególnie przydane jeśli pracujemy w większej grupie lub musimy wracać do starszych projektów których już nie pamiętamy, choć też i w małych jednoosobowych aplikacjach warto skorzystać z tego rozwiązania.
Tworząc klasę singleton'u chcemy aby tylko jeden obiekt istniał w całym systemie, tak aby zawsze mieć dostęp do tych samych wartości niezależnie od miejsca wywołania. W większości popularnych języków programowania można to osiągnąć pisząc zwyczajnie:
Singleton to jeden z wielu wzorców projektowych i tak jak większość z nich może wydawać się nie potrzebnym komplikowaniem spraw które można rozwiązać w o wiele łatwiejszy sposób, jednak prawda jest taka, że w zamian zyskujemy przejrzystszy i bardziej wyspecjalizowany kod co jest szczególnie przydane jeśli pracujemy w większej grupie lub musimy wracać do starszych projektów których już nie pamiętamy, choć też i w małych jednoosobowych aplikacjach warto skorzystać z tego rozwiązania.
Tworząc klasę singleton'u chcemy aby tylko jeden obiekt istniał w całym systemie, tak aby zawsze mieć dostęp do tych samych wartości niezależnie od miejsca wywołania. W większości popularnych języków programowania można to osiągnąć pisząc zwyczajnie:
private class Single { private static const instance:Single = new Single(); private function Single():void { } public static function getInstance():Single { return instance; } }Niestety we Flash'u tak łatwo nie będzie, gdyż ten nie pozwala na tworzenie konstruktorów w przestrzeni private, dlatego najczęściej stosuje się obejście wymagające od osoby trzeciej podania parametru którego na pewno nie będzie znał:
public class Singleton { private static const instance:Singleton = new Singleton(getInstance); public var myVar:Number; public function Singleton(f:Function = null) { if(f != getInstance) throw new Error("Singleton nie moze byc powielany! Skorzystaj z getInstance()."); myVar = 5; } public static function getInstance():Singleton { return instance; } }I to w zasadzie tyle, choć po tym prostym przykładzie trudno stwierdzić jakieś konkretne zalety na rzecz Singleton'ów, dlatego pomyślmy o nieco bardziej rozbudowanej klasie, na przykład kontroli dźwięków w aplikacji. Zwykle w takim przypadku najlepiej trzymać dźwięki w jednym miejscu by wczytywać, odtwarzać i zatrzymywać je za jednym zamachem, a więc właściwie idealna sytuacja by wykorzystać taki singleton (w bardzo uproszczonej formie):
public class SoundControl { private static var instance:SoundControl; private var bIsLoading:Boolean; private var aQueue:Array; private var aSounds:Array; public function SoundControl(f:Function = null) { if(f != getInstance) throw new Error("SoundControl nie moze byc powielany! Skorzystaj z getInstance()."); aSounds = new Array(); aQueue = new Array(); } public function play(name:String):void { if(bIsLoading) { aQueue.push(name); } else { aSounds.push( new Sound(name) ); /* odtworz dzwiek */ } } public function stopAll():void { for each(var snd:Sound in aSounds) { snd.stop(); } aQueue = new Array(); } private function loadAll():void { bIsLoading = true; /* wczytaj wszystkie dzwieki i na koniec wywolaj onLoaded */ } private function onLoaded():void { bIsLoading = false; /* odtworz wszystkie dzwieki przechowywane w aQueue */ } public static function getInstance():Singleton { if(instance == null) { instance = new SoundControl(getInstance); instance.loadAll(); } return instance; } }Jak widać SoundControl robi całkiem sporo, jednak dla osoby "z zewnątrz" widoczne będą tylko trzy funkcje: getInstance(), play() oraz stopAll(), czyli właściwie wszystko czego by potrzebował do prawidłowego odgrywania dźwięków w aplikacji, zostawiając całą brudną robotę (kontrola głośności, przydzielanie kanałów, zwalnianie zasobów itp.) nam, twórcom klasy. Dodatkowo cały czas mamy pewność, że nikt nie stworzy sobie osobnego obiektu SoundControl i nie zacznie odtwarzać dźwięków na własną rękę by potem wszyscy główkowali skąd one pochodzą, przecież jeden jedyny obiekt SoundControl z którego wszyscy mieli korzystać nic o tych dźwiękach nie wie...