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...


