sobota, 20 października 2012

[HTML|JS|CSS] JavaScript Patterns: Wzorce projektowe

Wzorce projektowe znane z języków obiektowych nie zawsze są łatwe do zaimplementowania w języku JavaScript. Aby uzyskać podobny efekt, często należy znać pewne specyficzne konstrukcje JS. Poniżej przedstawiono trzy wzorce przez tzw Gang of Four
. Ich implementacja w JS jest nieco inna od tej, którą wszyscy znają z języków obiektowych.

  • Singleton

Jeżeli chcemy zapewnić, aby pewien obiekt był zinstancjonowany tylko raz, można skorzystać z faktu, że funkcja jest obiektem, który może posiadać własne properties.

function MyObject(){

 if(typeof MyObject.instance !== "undefined"){
  return MyObject.instance;
 }

 this.name = "MyObject";
 this.counter = 0;

 MyObject.instance = this;
}

var o1 = new MyObject();
o1.counter++;
var o2 = new MyObject();
console.log(o2.counter);

Program wypisze 1. Problemem jest, że statyczna instancja jest publiczna, aby tego uniknąć można skorzystać z konstrukcji closure.

  • Factory

Wzorzec przydatny przy tworzeniu całych rodzin obiektów. Ma on na celu umożliwienie podjęcia decyzji o tym, który dokładnie obiekt ma zostać stworzony, podczas pracy programu. JavaScript ułatwia implementację wzorca, ponieważ warto pamiętać, że obiekty są parami typu klucz - wartość.

function VehicleMaker(){}

VehicleMaker.prototype.printType = function(){
 console.log(this.type);
};

VehicleMaker.factory = function(type){
 var constr = type,
  newvehicle;

 if(typeof VehicleMaker[constr] !== "function"){
  throw {
   name: "Error",
   message: constr + " not found"
  };
 }

 if(typeof VehicleMaker[constr].prototype.printType !== 
  "function"){
  VehicleMaker[constr].prototype = new VehicleMaker();  
 } 
 newvehicle = new VehicleMaker[constr]();
 return newvehicle;
};

VehicleMaker.Car = function(){
 this.type = 'car';
};

VehicleMaker.Bike = function(){
 this.type = 'bike';
};

VehicleMaker.Bus = function(){
 this.type = 'bus';
};

var bus = VehicleMaker.factory('Bus');
var car = VehicleMaker.factory('Car');
var bike = VehicleMaker.factory('Bike');

bus.printType();
car.printType();
bike.printType();

try{
 var whatever = VehicleMaker.factory('whatever');
}
catch(err){
 console.log(err);
}

  • Decorator

Wzorzec pozwala rozszerzać w pewien sposób jakiś obiekt w czasie pracy programu, bez z góry narzuconych reguł. Każdy obiekt po dekoracji zachowuje swoje właściwości plus dodatkowo dostaje coś ekstra. W przypadku języka JS do implementacji można wykorzystać listę dekoratorów i odpowiednią metodę, która wykona ich zadania gdy przyjdzie na to czas.

function Degree(name){
 this.name = name;
 this.decorators_list = [];
}

Degree.decorators = {};

Degree.decorators.Engineer = {
 getDegree: function(name){
  return "inz. " + name;
 }
};

Degree.decorators.Doctor = {
 getDegree: function(name){
  return "dr " + name;
 }
};

Degree.decorators.Professor = {
 getDegree: function(name){
  return "Prof. " + name;
 }
};

Degree.decorators.Print = {
 getDegree: function(name){
  console.log(name);
 }
};

Degree.prototype.decorate = function(decorator){
 this.decorators_list.push(decorator);
};

Degree.prototype.getDegree = function(){
 var fname = this.name,
  i,
  max = this.decorators_list.length,
  name;
 for(i = 0; i < max; i+=1){
  name = this.decorators_list[i];
  fname = Degree.decorators[name].getDegree(fname); 
 }
 return fname;
};

var prof = new Degree("Jan Kowalski");
prof.decorate('Engineer');
prof.decorate('Doctor');
prof.decorate('Professor');
console.log(prof.getDegree());

Brak komentarzy:

Prześlij komentarz