Strona wykorzystuje ciasteczka by usprawnić komfort z jej korzystania. Korzystając ze strony akceptujesz naszą Politykę Ciasteczek. X

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