Паттерн Посетитель (Visitor pattern) определяет операцию, выполняемую на каждом элементе некоторой структуры. Позволяет, не изменяя классы этих объектов, добавлять в них новые операции. Как известно, различные и несвязные операции выполняются над узловыми
объектами некоторой гетерогенной совокупной структуры. Чтобы избежать "загрязнения" классов этих узлов такими операциями (то есть избежать добавления соответствующих методов в эти классы), можно воспользоваться паттерном Посетитель. Также в реализации этого паттерна играют роль типы объектов, что позволяет делать типизированный выбор действий. Так как мы имеем дело с Javascript, то здесь это делается немного иначе: через условные конструкции. Данный паттерн относится к паттернам поведения. Ниже редставлена диаграмма классов реализации данного паттерна.
Также ниже представлен пример реализации данного паттерна.
/* internal iterator */
Array.prototype.iterator = function () {
var self = this, position = 0, undefined;
return {
next: function () {
return self[position++];
},
hasNext: function () {
if (position >= self.length) {
return false;
}
else {
return true;
}
},
remove: function () {
if (position <= 0) {
throw new Error("You can`t an item until you`ve done at least one next()");
}
if (self[position - 1] !== undefined) {
for (var i = position - 1; i < (self.length - 1); i++) {
self[i] = self[i + 1];
}
self[self.length - 1] = undefined;
}
}
};
};
/* interface Element */
var ComputerPart = function () {
this.accept = function (computerPartVisitor) {
throw new Error("accept method is not implemented");
};
};
/* ConcreteElement */
var Keyboard = function () {
this.accept = function (computerPartVisitor) {
computerPartVisitor.visit(this);
};
};
Keyboard.prototype = new ComputerPart();
Keyboard.prototype.constructor = Keyboard;
/* ConcreteElement */
var Monitor = function () {
this.accept = function (computerPartVisitor) {
computerPartVisitor.visit(this);
};
};
Monitor.prototype = new ComputerPart();
Monitor.prototype.constructor = Monitor;
/* ConcreteElement */
var Mouse = function () {
this.accept = function (computerPartVisitor) {
computerPartVisitor.visit(this);
};
};
Mouse.prototype = new ComputerPart();
Mouse.prototype.constructor = Mouse;
/* ConcreteElement */
var Computer = function () {
var parts = [new Mouse(), new Keyboard(), new Monitor()];
this.accept = function (computerPartVisitor) {
for (var it = parts.iterator(); it.hasNext();) {
(it.next()).accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
};
};
Computer.prototype = new ComputerPart();
Computer.prototype.constructor = Computer;
/* interface Visitor */
var computerPartVisitor = function () {
this.visit = function (computerPart) {
throw new Error("visit method is not implemented");
};
};
/* ConcreteVisitor */
var computerPartDisplayVisitor = function () {
this.visit = function (computerPart) {
if (computerPart.constructor === Computer) {
console.log("Displaying Computer.");
}
if (computerPart.constructor === Mouse) {
console.log("Displaying Mouse.");
}
if (computerPart.constructor === Keyboard) {
console.log("Displaying Keyboard.");
}
if (computerPart.constructor === Monitor) {
console.log("Displaying Monitor.");
}
};
};
computerPartDisplayVisitor.prototype = new computerPartVisitor();
computerPartDisplayVisitor.constructor = computerPartDisplayVisitor;
/* testing... */
var Application = function () {
this.run = function () {
var computer = new Computer();
computer.accept(new computerPartDisplayVisitor());
};
};
var app = new Application();
app.run();
В итоге получаем:
Displaying Mouse.
Displaying Keyboard.
Displaying Monitor.
Displaying Computer.
Всем успехов.