html/css. Create tables by using the div tags

<div class="Table">
<div class="Title">This is a Table</div>

<div class="Heading">
<div class="Cell">Heading 1</div>
<div class="Cell">Heading 2</div>
<div class="Cell">Heading 3</div>
</div>

<div class="Row">
<div class="Cell">Row 1 Column 1</div>
<div class="Cell">Row 1 Column 2</div>
<div class="Cell">Row 1 Column 3</div>
</div>

<div class="Row">
<div class="Cell">Row 2 Column 1</div>
<div class="Cell">Row 2 Column 2</div>
<div class="Cell">Row 2 Column 3</div>
</div>
</div>

<style type="text/css">

.Table {
  display: table;
}

.Title {
  display: table-caption;
  text-align: center;
  font-weight: bold;
  font-size: larger;
}

.Heading {
  display: table-row;
  font-weight: bold;
  text-align: center;
}

.Row {
  display: table-row;
}

.Cell {
  display: table-cell;
  border: solid;
  border-width: thin;
  padding-left: 5px;
  padding-right: 5px;
}

</style>

Javascript. Abstract Factory pattern

Паттерн Абстрактная фабрика (Abstract Factory pattern) предоставляет интерфейс для создания семейств взаимосвязанных объектов без указания их конкретных классов. Задача Абстрактной Фабрики - создание семейств взаимосвязанных объектов без зависимости от их конкретных классов. В то время как задача Фабричного Метода - перемещение создания экземпляров в субклассы. Данный паттерн вместе с паттерном Фабричный Метод инкапсулируют создание объектов, обеспечивая слабую связанность и гибкость архитектур. Данный паттерн относится к порождающим паттернам. Рассмотрим пару реализаций паттерна.


var Employee = function(name) {
    this.name = name;
    this.say = function () {
        log.add("I am employee " + name);
    };
};

var EmployeeFactory = function () {
    this.create = function(name) {
        return new Employee(name);
    };
};

var Vendor = function (name) {
    this.name = name;
    this.say = function () {
        log.add("I am vendor " + name);
    };
};

var VendorFactory = function () {
    this.create = function(name) {
        return new Vendor(name);
    };
};

// log helper
var log = (function () {
    var log = "";   
    return {
        add: function (msg) { log += msg + "\n"; },
        show: function () { console.log(log); log = ""; }
    };
})();

/* testing */

var Application = function () {
    this.run = function () {
        var persons = [],
            employeeFactory = new EmployeeFactory(),
            vendorFactory = new VendorFactory();
       
        persons.push(employeeFactory.create("Joan DiSilva"));
        persons.push(employeeFactory.create("Tim O'Neill"));
        persons.push(vendorFactory.create("Gerald Watson"));
        persons.push(vendorFactory.create("Nicole McNight"));
       
        for (var i = 0, len = persons.length; i < len; i++) {
            persons[i].say();
        }
       
        log.show();
    };
};

var app = new Application();
app.run();


На выходе

I am employee Joan DiSilva
I am employee Tim O'Neill
I am vendor Gerald Watson
I am vendor Nicole McNight


Или вот такая монструозная реализация. В данной реализации представлены фабрики пицц и входящих в них ингридиентов.

/* interface AbstractFactory */

var PizzaIngredientFactory = function () {
    this.createDough = function () {};
    this.createSauce = function () {};
    this.createCheese = function () {};
    this.createVeggies = function () {};
    this.createPepperoni = function () {};
    this.createClam = function () {};
};

/* ConcreteFactory - NYPizzaIngredientFactory */

var NYPizzaIngredientFactory = function () {
  
    this.createDough = function () {
        return new ThinCrustDough();
    };
  
    this.createSauce = function () {
        return new MarinaraSauce();
    };
  
    this.createCheese = function () {
        return new ReggianoCheese();
    };
  
    this.createVeggies = function () {
        var veggies = [
            new Garlic(),
            new Onion(),
            new Mushroom(),
            new RedPepper()
        ];
        return veggies;
    };
  
    this.createPepperoni = function () {
        return new SlicedPepperoni();
    };
  
    this.createClam = function () {
        return new FreshClams();
    };
  
};

NYPizzaIngredientFactory.prototype = new PizzaIngredientFactory();
NYPizzaIngredientFactory.prototype.constructor = NYPizzaIngredientFactory;

/* ConcreteFactory - ChicagoPizzaIngredienFactory */


var ChicagoPizzaIngredienFactory = function () {
  
    this.createDough = function () {
        return new ThinCrustDough();
    };
  
    this.createSauce = function () {
        return new PlumTomatoSauce();
    };
  
    this.createCheese = function () {
        return new MozzarellaCheese();
    };
  
    this.createVeggies = function () {
        var veggies = [
            new BlackOlives(),
            new Spinach(),
            new Eggplant()
        ];
        return veggies;
    };
  
    this.createPepperoni = function () {
        return new SlicedPepperoni();
    };
  
    this.createClam = function () {
        return new FrozenClams();
    };
  
};

ChicagoPizzaIngredienFactory.prototype = new PizzaIngredientFactory();
ChicagoPizzaIngredienFactory.prototype.constructor = ChicagoPizzaIngredienFactory;

/* AbstractProduct - interface Veggies */

var Veggies = function () {
    this.toString = function () {};
};

/* AbstractProduct - interface Cheese */

var Cheese = function () {
    this.toString = function () {};
};

/* AbstractProduct - interface Clams */

var Clams = function () {
    this.toString = function () {};
};

/* AbstractProduct - interface Dough */

var Dough = function () {
    this.toString = function () {};
};

/* AbstractProduct - interface Pepperoni */

var Pepperoni = function () {
    this.toString = function () {};
};

/* AbstractProduct - interface Sauce */

var Sauce = function () {
    this.toString = function () {};
};

/* ConcreteProduct - PlumTomatoSauce */

var PlumTomatoSauce = function () {
    this.toString = function () {
        return "Tomato sauce with plum tomatoes";
    };
};

PlumTomatoSauce.prototype = new Sauce();
PlumTomatoSauce.prototype.constructor = PlumTomatoSauce;

/* ConcreteProduct - RedPepper */


var RedPepper = function () {
    this.toString = function () {
        return "Red Pepper";
    };
};

RedPepper.prototype = new Veggies();
RedPepper.prototype.constructor = RedPepper;

/* ConcreteProduct - ReggianoCheese */

var ReggianoCheese = function () {
    this.toString = function () {
        return "Reggiano Cheese";
    };
};

ReggianoCheese.prototype = new Cheese();
ReggianoCheese.prototype.constructor = ReggianoCheese;

/* ConcreteProduct - SlicedPepperoni */

var SlicedPepperoni = function () {
    this.toString = function () {
        return "Sliced Pepperoni";
    };
};

SlicedPepperoni.prototype = new Pepperoni();
SlicedPepperoni.prototype.constructor = SlicedPepperoni;

/* ConcreteProduct - Spinach */

var Spinach = function () {
    this.toString = function () {
        return "Spinach";
    };
};

Spinach.prototype = new Veggies();
Spinach.prototype.constructor = Spinach;

/* ConcreteProduct - ThickCrustDough */

var ThickCrustDough = function () {
    this.toString = function () {
        return "ThickCrust style extra thick crust dough";
    };
};

ThickCrustDough.prototype = new Dough();
ThickCrustDough.prototype.constructor = ThickCrustDough;

/* ConcreteProduct - ThinCrustDough */

var ThinCrustDough = function () {
    this.toString = function () {
        return "Thin Crust Dough";
    };
};

ThinCrustDough.prototype = new Dough();
ThinCrustDough.prototype.constructor = ThinCrustDough;

/* ConcreteProduct - ParmesanCheese */

var ParmesanCheese = function () {
    this.toString = function () {
        return "Shredded Parmesan";
    };
};

ParmesanCheese.prototype = new Cheese();
ParmesanCheese.prototype.constructor = ParmesanCheese;

/* ConcreteProduct - Onion */

var Onion = function () {
    this.toString = function () {
        return "Onion";
    };
};

Onion.prototype = new Veggies();
Onion.prototype.constructor = Onion;

/* ConcreteProduct - Mushroom */

var Mushroom = function () {
    this.toString = function () {
        return "Mushrooms";
    };
};

Mushroom.prototype = new Veggies();
Mushroom.prototype.constructor = Mushroom;

/* ConcreteProduct - MozzarellaCheese */

var MozzarellaCheese = function () {
    this.toString = function () {
        return "Shredded Mozzarella";
    };
};

MozzarellaCheese.prototype = new Cheese();
MozzarellaCheese.prototype.constructor = MozzarellaCheese;

/* ConcreteProduct - MarinaraSauce */

var MarinaraSauce = function () {
    this.toString = function () {
        return "Marinara Sauce";
    };
};

MarinaraSauce.prototype = new Sauce();
MarinaraSauce.prototype.constructor = MarinaraSauce;

/* ConcreteProduct - Garlic */

var Garlic = function () {
    this.toString = function () {
        return "Garlic";
    };
};

Garlic.prototype = new Clams();
Garlic.prototype.constructor = Garlic;

/* ConcreteProduct - FrozenClams */

var FrozenClams = function () {
    this.toString = function () {
        return "Frozen Clams from Chesapeake Bay";
    };
};

FrozenClams.prototype = new Clams();
FrozenClams.prototype.constructor = FrozenClams;

/* ConcreteProduct - FreshClams */

var FreshClams = function () {
    this.toString = function () {
        return "Fresh Clams from Long Island Sound";
    };
};

FreshClams.prototype = new Clams();
FreshClams.prototype.constructor = FreshClams;

/* ConcreteProduct - Eggplant */

var Eggplant = function () {
    this.toString = function () {
        return "Eggplant";
    };
};

Eggplant.prototype = new Veggies();
Eggplant.prototype.constructor = Eggplant;

/* ConcreteProduct - BlackOlives */

var BlackOlives = function () {
    this.toString = function () {
        return "Black Olives";
    };
};

BlackOlives.prototype = new Veggies();
BlackOlives.prototype.constructor = BlackOlives;

/* AbstractClient - Pizza */

var Pizza = function () {

    // abstract prepare();
  
    this.bake = function () {
        console.log("Bake for 25 minutes at 350");
    };
  
    this.cut = function () {
        console.log("Cutting the pizza into diagonal slices");
    };
  
    this.box = function () {
        console.log("Place pizza in official PizzaStore box");
    };
  
    this.setName = function (name) {
        this.name = name;
    };
  
    this.getName = function () {
        return this.name;
    };
  
    this.toString = function () {
        var result = "";
        result += "---- " + this.name + " ----\n";
        if (this.dough) {
            result += this.dough;
            result += "\n";
        }
        if (this.sauce) {
            result += this.sauce;
            result += "\n";
        }
        if (this.cheese) {
            result += this.cheese;
            result += "\n";
        }
        if (this.veggies) {
            for (var i = 0; i < this.veggies.length; i++) {
                result += this.veggies[i];
                if (i < this.veggies.length - 1) {
                    result += ", ";
                }
            }
            result += "\n";
        }
        if (this.clam) {
            result += this.clam;
            result += "\n";
        }
        if (this.pepperoni) {
            result += this.pepperoni;
            result += "\n";
        }
        return result;
    };

};

/* ConcreteClient - PepperoniPizza */

var PepperoniPizza = function (ingredientFactory) {

    var ingredientFactory = ingredientFactory;
  
    this.prepare = function () {
        console.log("Preparing " + this.name);
        this.dough = ingredientFactory.createDough();
        this.sauce = ingredientFactory.createSauce();
        this.cheese = ingredientFactory.createCheese();
        this.veggies = ingredientFactory.createVeggies();
        this.pepperoni = ingredientFactory.createPepperoni();
    };

};

PepperoniPizza.prototype = new Pizza();
PepperoniPizza.prototype.constructor = PepperoniPizza();

/* ConcreteClient - CheesePizza */

var CheesePizza = function (ingredientFactory) {

    var ingredientFactory = ingredientFactory;
  
    this.prepare = function () {
        console.log("Preparing " + this.name);
        this.dough = ingredientFactory.createDough();
        this.sauce = ingredientFactory.createSauce();
        this.cheese = ingredientFactory.createCheese();
    };

};

CheesePizza.prototype = new Pizza();
CheesePizza.prototype.constructor = CheesePizza();

/* ConcreteClient - ClamPizza */

var ClamPizza = function (ingredientFactory) {

    var ingredientFactory = ingredientFactory;
  
    this.prepare = function () {
        console.log("Preparing " + this.name);
        this.dough = ingredientFactory.createDough();
        this.sauce = ingredientFactory.createSauce();
        this.cheese = ingredientFactory.createCheese();
        this.clam = ingredientFactory.createClam();
    };

};

ClamPizza.prototype = new Pizza();
ClamPizza.prototype.constructor = ClamPizza();

/* ConcreteClient - VeggiePizza */

var VeggiePizza = function (ingredientFactory) {

    var ingredientFactory = ingredientFactory;
  
    this.prepare = function () {
        console.log("Preparing " + this.name);
        this.dough = ingredientFactory.createDough();
        this.sauce = ingredientFactory.createSauce();
        this.cheese = ingredientFactory.createCheese();
        this.clam = ingredientFactory.createClam();
    };

};

VeggiePizza.prototype = new Pizza();
VeggiePizza.prototype.constructor = VeggiePizza();

/* Creator - PizzaStore */

var PizzaStore = function () {

    this.orderPizza = function (type) {
        var pizza = this.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza
    };

    // abstract createPizza(item);

};

/* ConcreteCreator - NYPizzaStore */

var NYPizzaStore = function () {
    // factory method
    this.createPizza = function (item) {
        var pizza = null;
        var ingredientFactory = new NYPizzaIngredientFactory();
      
        if (item === "cheese") {

            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("New York Style Cheese Pizza");

        } else if (item === "veggie") {

            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("New York Style Veggie Pizza");

        } else if (item === "clam") {

            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("New York Style Clam Pizza");

        } else if (item === "pepperoni") {

            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("New York Style Pepperoni Pizza");

        }
        return pizza;
    };
};

NYPizzaStore.prototype = new PizzaStore();
NYPizzaStore.prototype.constructor = NYPizzaStore;

/* ConcreteCreator - NYPizzaStore */

var ChicagoPizzaStore = function () {
    // factory method
    this.createPizza = function (item) {
        var pizza = null;
        var ingredientFactory = new NYPizzaIngredientFactory();
      
        if (item === "cheese") {

            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("Chicago Style Cheese Pizza");

        } else if (item === "veggie") {

            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("Chicago Style Veggie Pizza");

        } else if (item === "clam") {

            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("Chicago Style Clam Pizza");

        } else if (item === "pepperoni") {

            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("Chicago Style Pepperoni Pizza");

        }
        return pizza;
    };
};

ChicagoPizzaStore.prototype = new PizzaStore();
ChicagoPizzaStore.prototype.constructor = ChicagoPizzaStore;

/* test application */

var Application = function () {
    this.run = function () {
      
        var nyStore = new NYPizzaStore();
        var chicagoStore = new ChicagoPizzaStore();

        var pizza = nyStore.orderPizza("cheese");
        console.log("Ethan ordered a " + pizza + "\n");

        pizza = chicagoStore.orderPizza("cheese");
        console.log("Joel ordered a " + pizza + "\n");

        pizza = nyStore.orderPizza("clam");
        console.log("Ethan ordered a " + pizza + "\n");

        pizza = chicagoStore.orderPizza("clam");
        console.log("Joel ordered a " + pizza + "\n");

        pizza = nyStore.orderPizza("pepperoni");
        console.log("Ethan ordered a " + pizza + "\n");

        pizza = chicagoStore.orderPizza("pepperoni");
        console.log("Joel ordered a " + pizza + "\n");

        pizza = nyStore.orderPizza("veggie");
        console.log("Ethan ordered a " + pizza + "\n");

        pizza = chicagoStore.orderPizza("veggie");
        console.log("Joel ordered a " + pizza + "\n");
      
    };
};

var application = new Application();
application.run();


На выходе:

Preparing New York Style Cheese Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a ---- New York Style Cheese Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese

Preparing Chicago Style Cheese Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Joel ordered a ---- Chicago Style Cheese Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese

Preparing New York Style Clam Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a ---- New York Style Clam Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese
Fresh Clams from Long Island Sound

Preparing Chicago Style Clam Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Joel ordered a ---- Chicago Style Clam Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese
Fresh Clams from Long Island Sound

Preparing New York Style Pepperoni Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a ---- New York Style Pepperoni Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese
Garlic, Onion, Mushrooms, Red Pepper
Sliced Pepperoni

Preparing Chicago Style Pepperoni Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Joel ordered a ---- Chicago Style Pepperoni Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese
Garlic, Onion, Mushrooms, Red Pepper
Sliced Pepperoni

Preparing New York Style Veggie Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a ---- New York Style Veggie Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese
Fresh Clams from Long Island Sound

Preparing Chicago Style Veggie Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Joel ordered a ---- Chicago Style Veggie Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese
Fresh Clams from Long Island Sound


Если у вас возникло желание получше разобрать данный пример, то лучше обратиться к книжке "Паттерны проектирования. Эрик Фримен, Элизабет Фримен, Кэтти Сьерра, Берт Бейтс".

Javascript. Prototype pattern

Паттерн Прототип (Prototype pattern) используется в тех случаях, когда создание экземпляра класса требует больших затрат ресурсов или занимает много времени. То есть определяет интерфейс создания объекта через клонирование другого объекта вместо создания через конструктор. Данный паттерн относится к порождающим шаблонам. Ниже приведены примеры реализации данного паттерна.

/* Cars */

var Nissan = function () {
    this.bodyType = 'sedan';
    this.numberOfWheels = 4;
    this.power = 100;
};

var Audi = function () {
    this.bodyType = 'sedan';
    this.numberOfWheels = 4;
    this.power = 150;
};

var Bmw = function () {
    this.bodyType = 'sedan';
    this.numberOfWheels = 4;
    this.power = 120;
};

/* CarFactory */

var CarFactory = function (nissan, audi, bmw) {
    if (nissan.constructor !== Nissan ||
        audi.constructor !== Audi ||
        bmw.constructor !== Bmw) {
        throw new Error("In argument given not instance");
    }
   
    var nissan = nissan,
        audi = audi,
        bmw = bmw;
   
    var isArray = function (object) {
        return Object.prototype.toString.call(object) === '[object Array]';
    };
   
    var    isObject = function (object) {
        return Object.prototype.toString.call(object) === '[object Object]';
    };
   
    var clone = function (proto) {
        var newObject;  
      
        // for copying arrays
        if (isArray(proto)) {
            newObject = [];
            for (var i = 0, item, size = proto.length; i < size; i++) {
                if (isArray(proto[i]) || isObject(proto[i])) {
                    item = this.clone(proto[i]);
                }
                else {
                    item = proto[i];
                }
                newObject = newObject.concat(item);
            }          
        }
        // for copying objects
        else if (isObject(proto)) {
            newObject = {};          
            for (var property in proto) {
                if (proto.hasOwnProperty(property)) {
                    if (isArray(proto[i]) || isObject(proto[i])) {
                        newObject[property] = this.copy(proto[property]);
                    }
                    else {
                        newObject[property] = proto[property];
                    }
                }
            }   
        }
        // for copying other elements
        else {      
            newObject = proto;
        }
      
        return newObject;
    };
   
    this.getNissan = function () {
        return clone(nissan);
    };
   
    this.getAudi = function () {
        return clone(audi);
    };
   
    this.getBmw = function () {
        return clone(bmw);
    };
};

/* testing... */

var Application = function () {
    this.run = function () {
        var nissanPrototype = new Nissan(),
            audiPrototype = new Audi(),
            bmwPrototype = new Bmw();
       
        var factory = new CarFactory(nissanPrototype, audiPrototype, bmwPrototype);
       
        var nissan = factory.getNissan(),
            audi = factory.getAudi(),
            bmw = factory.getBmw();
    };
};


Данный пример реализован с помощью "фабричного" подхода. Вот иные реализации.

var ObjectPrototype = function (proto) {
   
    var isArray = function (object) {
        return Object.prototype.toString.call(object) === '[object Array]';
    };
   
    var    isObject = function (object) {
        return Object.prototype.toString.call(object) === '[object Object]';
    };
   
    this.copy = function (proto) {     
        var newObject; 
     
        // for copying arrays
        if (isArray(proto)) {
            newObject = [];
            for (var i = 0, item, size = proto.length; i < size; i++) {
                if (isArray(proto[i]) || isObject(proto[i])) {
                    item = this.copy(proto[i]);
                }
                else {
                    item = proto[i];
                }
                newObject = newObject.concat(item);
            }         
        }
        // for copying objects
        else if (isObject(proto)) {
            newObject = {};         
            for (var property in proto) {
                if (proto.hasOwnProperty(property)) {
                    if (isArray(proto[i]) || isObject(proto[i])) {
                        newObject[property] = this.copy(proto[property]);
                    }
                    else {
                        newObject[property] = proto[property];
                    }
                }
            }         
        }
        // for copying other elements
        else {     
            newObject = proto;
        }
     
        return newObject;     
    };
};

var Man = function (name) {
    // some man properties...
};

var Woman = function (name) {
    // some woman properties...
};

var Application = function () {
    this.run = function () {
        var Adam = new Man('Adam');
        var AdamPrototype = new ObjectPrototype(Adam);
        var AdamClone = AdamPrototype.clone();
       
        var Eva = new Man('Eva');
        var EvaPrototype = new ObjectPrototype(Eva);
        var EvaClone = EvaPrototype.clone();
       
        // working with Adan & Eva clones
    };
};


Можно ObjectPrototype конкретизировать с помощью целевых классов.

var ObjectPrototype = function (proto) {
   
    var isArray = function (object) {
        return Object.prototype.toString.call(object) === '[object Array]';
    };
   
    var    isObject = function (object) {
        return Object.prototype.toString.call(object) === '[object Object]';
    };
   
    this.copy = function (proto) {     
        var newObject; 
     
        // for copying arrays
        if (isArray(proto)) {
            newObject = [];
            for (var i = 0, item, size = proto.length; i < size; i++) {
                if (isArray(proto[i]) || isObject(proto[i])) {
                    item = this.copy(proto[i]);
                }
                else {
                    item = proto[i];
                }
                newObject = newObject.concat(item);
            }         
        }
        // for copying objects
        else if (isObject(proto)) {
            newObject = {};         
            for (var property in proto) {
                if (proto.hasOwnProperty(property)) {
                    if (isArray(proto[i]) || isObject(proto[i])) {
                        newObject[property] = this.copy(proto[property]);
                    }
                    else {
                        newObject[property] = proto[property];
                    }
                }
            }         
        }
        // for copying other elements
        else {     
            newObject = proto;
        }
     
        return newObject;     
    };
};

/* Customers */

var Customer = function (name, orders) {
    this.name = name || '';
    this.orders = orders || 0;
    this.setOrders = function (orders) {
        this.orders = orders;
    };
    this.getOrders = function () {
        return this.orders;
    };
};

var CustomerPrototype = function (customer) {
    if (!(customer instanceof Customer)) {
        throw new Error("Given argument is not Customer type");
    }
    this.setProto = function (_customer) {
        if (!(_customer instanceof Customer)) {
            throw new Error("Given argument is not Customer type");
        }
        customer = _customer;
    };
    this.getProto = function () {
        return this.copy(customer);
    };
};
CustomerPrototype.prototype = new ObjectPrototype();

CustomerPrototype.prototype.constructor = CustomerPrototype;
 
/* Sellers */

var Seller = function (name, sales) {
    this.name = name || '';
    this.sales = sales || 0;
    this.setSales = function (sales) {
        this.sales = sales;
    };
    this.getSales = function () {
        return this.sales;
    };
};

var SellerPrototype = function (seller) {
    if (!(seller instanceof Seller)) {
        throw new Error("Given argument is not Seller type");
    }
    this.setProto = function (_seller) {
        if (!(_seller instanceof Seller)) {
            throw new Error("Given argument is not Seller type");
        }
        seller = _seller;
    };
    this.getProto = function () {
        return this.copy(seller);
    };
};
SellerPrototype.prototype = new ObjectPrototype();

SellerPrototype.prototype.constructor = SellerPrototype;

/* testing... */

var Application = function () {
    this.run = function () {
        var Nik = new Customer('Nik', 125),
            NikCustomerPrototype = new CustomerPrototype(Nik),
            NikColleague = NikCustomerPrototype.getProto();
       
        console.log("Nik and his colleague have " + (Nik.getOrders() + NikColleague.getOrders()) + " orders");
       
        var Merry = new Seller('Merry', 16),
            MerrySellerPrototype = new SellerPrototype(Merry),
            FirstColleague = MerrySellerPrototype.getProto();
        MerrySellerPrototype.setProto(new Seller('Merry', 20));
        var SecondColleague = MerrySellerPrototype.getProto();
       
        console.log("Merry and her colleagues have " + (FirstColleague.getSales() + SecondColleague.getSales()) + " sales");
    };
};

var app = new Application();
app.run();


На выходе

Nik and his colleague have 250 orders
Merry and her colleagues have 36 sales

Javascript. Flyweight pattern

Паттерн Приспособленец (Flyweight pattern) используется в случае, если один экземпляр класса может предоставлять много "виртуальных экземпляров". То есть вместо создания тысяч объектов определенного типа, можно создать один объект, который будет хранить состояние всех этих объектов. Данный паттерн нашел себя в системах с критическими требованиям к ресурсам. Паттерн относится к структурным паттернам. В общем виде uml диаграмма данного паттерна выглядит следующим образом.


Рассмотрим конкретный пример реализации.

/* Flyweight interface */

var Shape = function () {
this.draw = function () {};
}

/* ConcreteFlyweight */

var Circle = function (color) {
var color = color,
x,
y,
radius;

this.setX = function (_x) {
x = _x;
};

this.setY = function (_y) {
y = _y;
};

this.setRadius = function (_radius) {
radius = _radius;
};

this.draw = function () {
console.log("Circle: Draw() [Color: " + color +
", x: " + x + ", y: " + y + ", radius: " + radius);
};
};

Circle.prototype = new Shape();
Circle.prototype.constructor = Circle;

/* FlyweightFactory */
var ShapeFactory = (function () {
var circleMap = {},
getCircle = function (color) {
var circle = circleMap[color] || null;
if (circle === null) {
circle = new Circle(color);
circleMap[color] = circle;
console.log("Creating circle of color: " + color);
}
return circle;
},
ShapeFactory = function () {};

ShapeFactory.getCircle = getCircle;
return ShapeFactory;
})(); 

// testing...

var Application = function () {
var colors = ["Red", "Green", "Blue", "White", "Black"],

getRandomColor = function () {
return parseInt((Math.random() * colors.length), 10);
},

getRandomX = function () {
return parseInt((Math.random() * 100), 10);
},

getRandomY = function () {
return parseInt((Math.random() * 100), 10);
};


this.run = function () {
for (var i = 0, circle; i < 20; ++i) {
circle = ShapeFactory.getCircle(getRandomColor());
circle.setX(getRandomX());
circle.setY(getRandomY());
circle.setRadius(100);
circle.draw();
}
};
};

var app = new Application();
app.run();

На выходе:

Creating circle of color: 2
Circle: Draw() [Color: 2, x: 48, y: 96, radius: 100
Creating circle of color: 0
Circle: Draw() [Color: 0, x: 45, y: 33, radius: 100
Creating circle of color: 3
Circle: Draw() [Color: 3, x: 52, y: 48, radius: 100
Circle: Draw() [Color: 3, x: 32, y: 64, radius: 100
Circle: Draw() [Color: 2, x: 70, y: 66, radius: 100
Creating circle of color: 4
Circle: Draw() [Color: 4, x: 46, y: 62, radius: 100
Circle: Draw() [Color: 2, x: 84, y: 49, radius: 100
Circle: Draw() [Color: 0, x: 57, y: 57, radius: 100
Circle: Draw() [Color: 3, x: 12, y: 39, radius: 100
Circle: Draw() [Color: 3, x: 98, y: 90, radius: 100
Circle: Draw() [Color: 2, x: 9, y: 88, radius: 100
Circle: Draw() [Color: 3, x: 2, y: 68, radius: 100
Circle: Draw() [Color: 0, x: 69, y: 74, radius: 100
Circle: Draw() [Color: 2, x: 65, y: 91, radius: 100
Circle: Draw() [Color: 2, x: 57, y: 60, radius: 100
Circle: Draw() [Color: 2, x: 72, y: 24, radius: 100
Circle: Draw() [Color: 3, x: 34, y: 23, radius: 100
Circle: Draw() [Color: 3, x: 24, y: 13, radius: 100
Circle: Draw() [Color: 4, x: 62, y: 84, radius: 100
Circle: Draw() [Color: 3, x: 81, y: 22, radius: 100

Javascript. Chain of responsibility pattern

Паттерн Цепочка обязанностей (Chain of responsibility pattern) используется, когда вы хотите предоставить нескольким объектам возможность обработать запрос. То есть предназначен для организации в системе уровней ответственности. В паттерне создается цепочка объектов, последовательно анализирующих запрос. Каждый объект получает запрос и либо обрабатывает его, либо передает следующему объекту в цепочке. Данный шаблон относится к поведенческим шаблонам.

Ниже приведен очередной пример реализации паттерна на основе системы логирования определенных сообщений. Типу сообщения соответствует свой логер. Логеры составляют цепочку объектов-обработчиков поступающих сообщений.

var Logger = (function () {

    var Logger = function () {
    
        var next = null;
    
        this.setNext = function (log) {
            next = log;
            return log;
        };
        
        this.message = function (msg, priority) {
            if (priority <= this.mask) {
                this.writeMessage(msg);
            }
            if (next !== null) {
                next.message(msg, priority);
            }
        };

        // abstract protected writeMessage(msg)
    
    };
    
    Logger.ERR = 3;
    Logger.NOTICE = 5;
    Logger.DEBUG = 7;
    
    return Logger;
})();

var StdOutLogger = function (mask) {
    this.mask = mask;
    this.writeMessage = function (msg) {
        console.log("Writing to stdout: " + msg);
    };
};

StdOutLogger.prototype = new Logger();
StdOutLogger.prototype.constructor = StdOutLogger;

var EmailLogger = function (mask) {
    this.mask = mask;
    this.writeMessage = function (msg) {
        console.log("Sending via email: " + msg);
    };
};

EmailLogger.prototype = new Logger();
EmailLogger.prototype.constructor = EmailLogger;

var StdErrLogger = function (mask) {
    this.mask = mask;
    this.writeMessage = function (msg) {
        console.log("Sending to stderr: " + msg);
    };
};

StdErrLogger.prototype = new Logger();
StdErrLogger.prototype.constructor = StdErrLogger;

// testing...

var Application = function () {
    this.run = function () {    
        var logger, logger1, logger2;
        
        logger = new StdOutLogger(Logger.DEBUG);
        logger1 = logger.setNext(new EmailLogger(Logger.NOTICE));
        logger2 = logger1.setNext(new StdErrLogger(Logger.ERR));
        
        logger.message("Entering function y.", Logger.DEBUG);
        logger.message("Step1 completed.", Logger.NOTICE);
        logger.message("An error has occurred.", Logger.ERR);    
    };
};

var application = new Application();
application.run();

На выходе

Writing to stdout: Entering function y.
Writing to stdout: Step1 completed.
Sending via email: Step1 completed.
Writing to stdout: An error has occurred.
Sending via email: An error has occurred.
Sending to stderr: An error has occurred.

Javascript. Bridge pattern

Паттерн Мост (Bridge pattern) используют в том случае, когда может меняться не только реализация, но и абстракция. Для этого реализацию и абстракцию размещают в двух разных иерархиях классов (иерархия классов абстракции и иерархия классов реализации). Отношения между двумя иерархиями называется "мостом". Данный паттерн относится к структурным паттернам. Ниже приведена uml диаграмма данного паттерна.


Ниже приведен пример реализации паттерна.

/* Abstraction */

var Shape = function (color) {
    var color = color;
    
    this.setColor = function (_color) {
        color = _color;
    };
    
    this.getColor = function () {
        return color;
    };
    
    this.applyColor = function () {
        color.applyColor();
    };
};

/* RefinedAbstraction */

var Triangle = function (color) {
    var shape = new Shape(color);
    
    this.setColor = function (color) {
        shape.setColor(color);
    };
    
    this.getColor = function () {
        return shape.getColor();
    };
    
    this.applyColor = function () {
        console.log("Triangle filled with color ");
        shape.applyColor();
    };
};

/* RefinedAbstraction */

var Pentagon = function (color) {
    var shape = new Shape(color);
    
    this.setColor = function (color) {
        shape.setColor(color);
    };
    
    this.getColor = function () {
        return shape.getColor();
    };
    
    this.applyColor = function () {
        console.log("Pentagon filled with color ");
        shape.applyColor();
    };
};

/* Implementor */

var Color = function () {
    this.applyColor = function () {
        throw new Error("applyColor method is not implemented");
    };
};

/* ConcreteImplementor */

var RedColor = function () {
    this.applyColor = function () {
        console.log("red color");
    };
};

RedColor.prototype = new Color();
RedColor.prototype.constructor = RedColor;

/* ConcreteImplementor - GreenColor */

var GreenColor = function () {
    this.applyColor = function () {
        console.log("green color");
    };
};

GreenColor.prototype = new Color();
GreenColor.prototype.constructor = GreenColor;

/* testing... */

var Application = function () {
    this.run = function () {
        var triangle = new Triangle(new RedColor());
        var pentagon = new Pentagon(new GreenColor());
        
        triangle.applyColor();
        pentagon.applyColor();
        
        triangle.setColor(new GreenColor());
        pentagon.setColor(new RedColor());
        
        triangle.applyColor();
        pentagon.applyColor();
    };
};

var app = new Application();
app.run();

На выходе:

Triangle filled with color
red color
Pentagon filled with color
green color
Triangle filled with color
green color
Pentagon filled with color
red color

А вот этот же пример, только реализованный немного иначе.

/* Abstraction */

var Shape = function (color) {
    var color = color;
    
    this.setColor = function (_color) {
        color = _color;
    };
    
    this.getColor = function () {
        return color;
    };
    
    this.applyColor = function () {
        color.applyColor();
    };
};

/* RefinedAbstraction */

var Triangle = function (color) {
    Shape.call(this, color);
    
    var applyColor = this.applyColor;
    
    this.applyColor = function () {
        console.log("Triangle filled with color ");
        applyColor();
    };
};

/* RefinedAbstraction */

var Pentagon = function (color) {
    Shape.call(this, color);
    
    var applyColor = this.applyColor;
    
    this.applyColor = function () {
        console.log("Pentagon filled with color ");
        applyColor();
    };
};

/* Implementor */

var Color = function () {
    this.applyColor = function () {
        throw new Error("applyColor method is not implemented");
    };
};

/* ConcreteImplementor */

var RedColor = function () {
    this.applyColor = function () {
        console.log("red color");
    };
};

RedColor.prototype = new Color();
RedColor.prototype.constructor = RedColor;

/* ConcreteImplementor - GreenColor */

var GreenColor = function () {
    this.applyColor = function () {
        console.log("green color");
    };
};

GreenColor.prototype = new Color();
GreenColor.prototype.constructor = GreenColor;

/* testing... */

var Application = function () {
    this.run = function () {
        var triangle = new Triangle(new RedColor());
        var pentagon = new Pentagon(new GreenColor());
        
        triangle.applyColor();
        pentagon.applyColor();
        
        triangle.setColor(new GreenColor());
        pentagon.setColor(new RedColor());
        
        triangle.applyColor();
        pentagon.applyColor();
    };
};

var app = new Application();
app.run();