Паттерн Приспособленец (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.
Ниже приведен очередной пример реализации паттерна на основе системы логирования определенных сообщений. Типу сообщения соответствует свой логер. Логеры составляют цепочку объектов-обработчиков поступающих сообщений.
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
Ниже приведен пример реализации паттерна.
/* 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();
Javascript. Builder pattern
Паттерн Строитель (Builder pattern) инкапсулирует конструирование продукта и позволяет разделить его на этапы, тем самым инкапсулируется процесс создания сложного объекта. Данный паттерн относится к порождающим паттернам, дает возможность поэтапного конструирования объекта с переменным набором этапов (в отличие от "одноэтапных" фабрик). Также данный паттерн скрывает внутреннее представление продукта от клиента. Часто используется для создания составных структур. Ниже приводится пример реализации паттерна.
/* Director */
function Shop() {
this.construct = function(builder) {
builder.step1();
builder.step2();
return builder.get();
}
}
/* ConcreteBuilder */
function CarBuilder() {
this.car = null;
this.step1 = function() {
this.car = new Car();
};
this.step2 = function() {
this.car.addParts();
};
this.get = function() {
return this.car;
};
}
/* ConcreteBuilder */
function TruckBuilder() {
this.truck = null;
this.step1 = function() {
this.truck = new Truck();
};
this.step2 = function() {
this.truck.addParts();
};
this.get = function() {
return this.truck;
};
}
/* Product */
function Car() {
this.doors = 0;
this.addParts = function() {
this.doors = 4;
};
this.say = function() {
log.add("I am a " + this.doors + "-door car");
};
}
/* Product */
function Truck() {
this.doors = 0;
this.addParts = function() {
this.doors = 2;
};
this.say = function() {
log.add("I am a " + this.doors + "-door truck");
};
}
// 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 shop = new Shop(),
carBuilder = new CarBuilder(),
truckBuilder = new TruckBuilder(),
car = shop.construct(carBuilder),
truck = shop.construct(truckBuilder);
car.say();
truck.say();
log.show();
};
};
var app = new Application();
app.run();
На выходе имеем:
I am a 4-door car
I am a 2-door truck
Всем удачи в нашем нелегком пути :)
/* Director */
function Shop() {
this.construct = function(builder) {
builder.step1();
builder.step2();
return builder.get();
}
}
/* ConcreteBuilder */
function CarBuilder() {
this.car = null;
this.step1 = function() {
this.car = new Car();
};
this.step2 = function() {
this.car.addParts();
};
this.get = function() {
return this.car;
};
}
/* ConcreteBuilder */
function TruckBuilder() {
this.truck = null;
this.step1 = function() {
this.truck = new Truck();
};
this.step2 = function() {
this.truck.addParts();
};
this.get = function() {
return this.truck;
};
}
/* Product */
function Car() {
this.doors = 0;
this.addParts = function() {
this.doors = 4;
};
this.say = function() {
log.add("I am a " + this.doors + "-door car");
};
}
/* Product */
function Truck() {
this.doors = 0;
this.addParts = function() {
this.doors = 2;
};
this.say = function() {
log.add("I am a " + this.doors + "-door truck");
};
}
// 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 shop = new Shop(),
carBuilder = new CarBuilder(),
truckBuilder = new TruckBuilder(),
car = shop.construct(carBuilder),
truck = shop.construct(truckBuilder);
car.say();
truck.say();
log.show();
};
};
var app = new Application();
app.run();
На выходе имеем:
I am a 4-door car
I am a 2-door truck
Всем удачи в нашем нелегком пути :)
Javascript. Iterpretator pattern
Паттерн Интерпретатор (Iterpretator pattern - Little (Small) Language) используется для создания языковых интерпретаторов. Определяется представление своей грамматики в виде класса вместе с интерпретатором для обработки серий. В архитектуру вводится класс, представляющий каждое правило языка. Интерпретация языка осуществляется вызовом метода interpret() для каждого типа выражения. Метод получает контекст (содержащий входной поток разбираемой программы), идентифицирует входные данные и обрабатывает их. Данный паттерн относится к поведенческим паттернам. Ниже приведены примеры реализации паттерна.
var Expression = function () {
this.interpret = function () {
throw new Error("You have not implement abstract method");
};
};
var TerminalExpression = function (data) {
this.interpret = function (context) {
if (context.indexOf(data) >= 0) {
return true;
}
return false;
};
};
TerminalExpression.prototype = new Expression();
TerminalExpression.prototype.constructor = TerminalExpression;
var OrExpression = function (expr1, expr2) {
if (!(expr1 instanceof Expression) || !(expr2 instanceof Expression)) {
throw new Error("In argument given incorrect type");
}
this.interpret = function (context) {
return expr1.interpret(context) || expr2.interpret(context)
};
};
OrExpression.prototype = new Expression();
OrExpression.prototype.constructor = OrExpression;
var AndExpression = function (expr1, expr2) {
if (!(expr1 instanceof Expression) || !(expr2 instanceof Expression)) {
throw new Error("In argument given incorrect type");
}
this.interpret = function (context) {
return expr1.interpret(context) && expr2.interpret(context)
};
};
AndExpression.prototype = new Expression();
AndExpression.prototype.constructor = AndExpression;
var Application = function () {
//Rule: Robert and John are male
var getMaleExpression = function () {
var robert = new TerminalExpression("Robert"),
john = new TerminalExpression("John");
return new OrExpression(robert, john);
};
//Rule: Julie is a married women
var getMarriedWomanExpression = function () {
var julie = new TerminalExpression("Julie"),
married = new TerminalExpression("Married");
return new AndExpression(julie, married);
};
this.run = function () {
var isMale = getMaleExpression(),
isMarriedWoman = getMarriedWomanExpression();
console.log("John is male? " + isMale.interpret("John"));
console.log("Julie is a married women? " + isMarriedWoman.interpret("Married Julie"));
};
};
var app = new Application();
app.run();
На выходе:
John is male? true
Julie is a married women? true
Вот еще одна реализация (http://www.dofactory.com/javascript/interpreter-design-pattern).
var Context = function (input) {
this.input = input;
this.output = 0;
};
Context.prototype = {
startsWith : function (str) {
return this.input.substr(0, str.length) === str;
}
};
var Expression = function (name, one, four, five, nine, multiplier) {
this.name = name;
this.one = one;
this.four = four;
this.five = five;
this.nine = nine;
this.multiplier = multiplier;
};
Expression.prototype = {
interpret: function (context) {
if (context.input.length == 0) {
return;
}
else if (context.startsWith(this.nine)) {
context.output += (9 * this.multiplier);
context.input = context.input.substr(2);
}
else if (context.startsWith(this.four)) {
context.output += (4 * this.multiplier);
context.input = context.input.substr(2);
}
else if (context.startsWith(this.five)) {
context.output += (5 * this.multiplier);
context.input = context.input.substr(1);
}
while (context.startsWith(this.one)) {
context.output += (1 * this.multiplier);
context.input = context.input.substr(1);
}
}
};
var Application = function () {
this.run = function () {
var roman = "MCMXXVIII"
var context = new Context(roman);
var tree = [];
tree.push(new Expression("thousand", "M", " " , " ", " " , 1000));
tree.push(new Expression("hundred", "C", "CD", "D", "CM", 100));
tree.push(new Expression("ten", "X", "XL", "L", "XC", 10));
tree.push(new Expression("one", "I", "IV", "V", "IX", 1));
for (var i = 0, len = tree.length; i < len; i++) {
tree[i].interpret(context);
}
console.log(roman + " = " + context.output);
};
};
var app = new Application();
app.run();
На выходе получаем сообщение:
MCMXXVIII = 1928
Subscribe to:
Posts
(
Atom
)



