делегирование это когда есть объект, который перенаправляет методы в другой инкапсулированный объект. при этом, сам он не расширяет функциональность «вложенного» метода. если он что-то делает, а потом вызывает — это декоратор.
можно этот же пример сделать с помощью «не особо делегирования», нам понадобятся следующие классы: BaseScroll_plus_Buttons, BaseScroll_plus_PageNum, BaseScroll_plus_Buttons_plus_PageNum — и еще столько же для AnimScroll.
А если мы не хотим иметь шесть классов, то можно сделать метод компоненты и декораторы :)
я люблю всех посетителей сайта, даже ie-посетителей, даже тех, у которых отключен css/js, но в минимализме тоже меру надо знать, никто от лишних 5-50 килобайт не лопнет, это соизмеримо с одной картинкой. в «не лопнет» тоже надо меру знать.
dom-виджет я выбрал, потому что визуальный пример с формочкой всегда понятнее, чем код, или описание кода.
книгу надо бы почитать, спасибо за ссылку, но зацикливаться на ней я тоже буду :)
краткость кода это хорошо, но его модифицируемость — гораздо лучше. быстрый код? не думаю, что эта штука будет тормозить. а реализовывать функционал, требующий максимальной скорости нужно, как бы это, «на языке», без архитектуры вообще… не знаю, как это по-человечески сказать :)
у меня тоже есть отступления от темы. Scroll, и Decorator — базовые классы, а не интерфейсы, из-за локальных переменных.
я не зацикливаюсь, просто под декоратором люди понимают все, что угодно: AOP, колбэки, перекидывание функции (именно функции, у которой return число возвращает) аргументом при инстанцировании декоратора. «но мне бы хотелось поделиться реализацией весьма близкой к GoF'у».
пример имеет, по сути, один JS-недостаток — объем кода. это плохо, но, имхо, еще не причина оставлять его в рамках академического интереса.
а, если их не копировать, то как потом в декораторе вызывать?
т.е. у компонента есть fn2, а у декоратора его нет — как вызвать fn2, обращаясь к декоратору и не проверяя каждый раз наличие fn2?
именно перехватывать несуществующие методы нельзя, только если с помощью try/catch, но это или try/catch при каждом вызове каждого метода (полный бред), или велосипед ввиде отдельной функции, которой передаются имя метода и аргументы, и уже она проверяет typeof(this[methodName]), но тоже красотой не блещет.
можно вот такой велосипед придумать, но следует ли им пользоваться — большой вопрос…
function Component() {
this.fn1 = function(val) { alert("Component > fn1 " + val); };
this.fn2 = function(val) { alert("Component > fn2 " + val); };
}
function IDecorator() {
var dublicate = this;
var component;
this.setComponent = function(val) {
component = val;
for (var key in val) {
if (typeof(val[key])=="function") {
addMethod(key, val[key]);
}
}
};
this.getComponent = function() {
return component;
};
this.applyComponentMethod = function(name, argsArray) {
if (typeof(component[name])=="function") {
component[name].apply(dublicate, argsArray || []);
}
};
function addMethod(name, componentFn) {
dublicate[name] = function() {
return componentFn.apply(this, arguments || []);
}
}
}
function MyDecorator(component) {
var dublicate = this;
IDecorator.call(this);
this.setComponent(component);
this.fn1 = function(val) {
alert("MyDecorator > fn1 " + val);
dublicate.applyComponentMethod("fn1", [val]);
};
}
var c = new Component();
var d = new MyDecorator(c );
d.fn1(1); // "MyDecorator > fn1 1", "Component > fn1 1"
d.fn2(2); // "Component > fn2 2" и не думаю, что это хорошо
… но я бы лучше перечислял методы, ничего зазорного я в этом не вижу
не хотелось бы отвечать «где угодно» или копипастить, попробую «от души» ответить, голосом сердца :)
обычно, приступая к написанию чего-либо, мы изучаем что нам надо сделать и берем в рассчет только то, что от нас хотят. мы готовы к переделкам очень относительно, но пока наше творение находится «внутри функции», или там в объекте, то чтобы что-то переделать, нам надо или положиться на удачу, или изучить функционал целиком. надо переделать второй раз — снова или положиться на удачу, или изучить функционал целиком.
что бы то ни было: калькуляторы, фотогалереи, система сообщений между пользователями на сайте — корзина отдельно, яйца отдельно :)
только я не призываю юзать это везде. абсолютно не призываю. каждую задачу можно решить бесконечным числом способов и нету какого-то универсального.
калькулятор считает размер скидки. есть 5 критериев. их можно взять и написать один за другим. надо выкинуть 3й и добавить новый — изучаем всю логику и режем кусочки, или не лезем в логику рассчетов, а удаляем в конструкторе подключение 3-го и пишем еще один. конечно, не всегда можно найти 5 обособленных критериев.
фотогалерея уже нашлась в комментах, см. выше.
система сообщений между пользователями на сайте может отображать кол-во новых сообщений в статус баре, и когда понадобится добавить алерт о новом сообщении, мы сможем сделать это быстро, а когда понадобится его удалить, не будет никаких сомнений в работоспособности системы. хотя, имхо, тут лучше наблюдатель задействовать :)
повторюсь, я не призываю юзать декоратор везде, а только там, где это действительно профитно.
изначально, да, был чисто академический интерес. сначала посмотрел примеры, книгу почитал, написал на js абстрактное решение. потом начал думать о хоть каком-нибудь примере из реальной жизни, и додумался до вот такой штучки.
и вот когда я до неё додумался :) понял профитность реализации «как написано», а не как умею.
«деревянный велосипед» изобрели светила современного программирования, те самые GoF, вы можете погуглить что такое «шаблоны проектирования» (да ту же вики почитать).
вы не дочитали всего-навсего реализацию на JS с очень незначительными вариациями от классики, в отличие от множества других примеров декоратора когда «работоспособность остается», а профит от подхода много меньше.
делегирование это когда есть объект, который перенаправляет методы в другой инкапсулированный объект. при этом, сам он не расширяет функциональность «вложенного» метода. если он что-то делает, а потом вызывает — это декоратор.
можно этот же пример сделать с помощью «не особо делегирования», нам понадобятся следующие классы: BaseScroll_plus_Buttons, BaseScroll_plus_PageNum, BaseScroll_plus_Buttons_plus_PageNum — и еще столько же для AnimScroll.
А если мы не хотим иметь шесть классов, то можно сделать метод компоненты и декораторы :)
мой любимый тип опечаток
книгу надо бы почитать, спасибо за ссылку, но зацикливаться на ней я тоже буду :)
краткость кода это хорошо, но его модифицируемость — гораздо лучше. быстрый код? не думаю, что эта штука будет тормозить. а реализовывать функционал, требующий максимальной скорости нужно, как бы это, «на языке», без архитектуры вообще… не знаю, как это по-человечески сказать :)
у меня тоже есть отступления от темы. Scroll, и Decorator — базовые классы, а не интерфейсы, из-за локальных переменных.
я не зацикливаюсь, просто под декоратором люди понимают все, что угодно: AOP, колбэки, перекидывание функции (именно функции, у которой return число возвращает) аргументом при инстанцировании декоратора. «но мне бы хотелось поделиться реализацией весьма близкой к GoF'у».
пример имеет, по сути, один JS-недостаток — объем кода. это плохо, но, имхо, еще не причина оставлять его в рамках академического интереса.
ой, извиняюсь, поведение правильное
т.е. у компонента есть fn2, а у декоратора его нет — как вызвать fn2, обращаясь к декоратору и не проверяя каждый раз наличие fn2?
можно вот такой велосипед придумать, но следует ли им пользоваться — большой вопрос…
function Component() { this.fn1 = function(val) { alert("Component > fn1 " + val); }; this.fn2 = function(val) { alert("Component > fn2 " + val); }; } function IDecorator() { var dublicate = this; var component; this.setComponent = function(val) { component = val; for (var key in val) { if (typeof(val[key])=="function") { addMethod(key, val[key]); } } }; this.getComponent = function() { return component; }; this.applyComponentMethod = function(name, argsArray) { if (typeof(component[name])=="function") { component[name].apply(dublicate, argsArray || []); } }; function addMethod(name, componentFn) { dublicate[name] = function() { return componentFn.apply(this, arguments || []); } } } function MyDecorator(component) { var dublicate = this; IDecorator.call(this); this.setComponent(component); this.fn1 = function(val) { alert("MyDecorator > fn1 " + val); dublicate.applyComponentMethod("fn1", [val]); }; } var c = new Component(); var d = new MyDecorator(c ); d.fn1(1); // "MyDecorator > fn1 1", "Component > fn1 1" d.fn2(2); // "Component > fn2 2" и не думаю, что это хорошо… но я бы лучше перечислял методы, ничего зазорного я в этом не вижу
обычно, приступая к написанию чего-либо, мы изучаем что нам надо сделать и берем в рассчет только то, что от нас хотят. мы готовы к переделкам очень относительно, но пока наше творение находится «внутри функции», или там в объекте, то чтобы что-то переделать, нам надо или положиться на удачу, или изучить функционал целиком. надо переделать второй раз — снова или положиться на удачу, или изучить функционал целиком.
что бы то ни было: калькуляторы, фотогалереи, система сообщений между пользователями на сайте — корзина отдельно, яйца отдельно :)
только я не призываю юзать это везде. абсолютно не призываю. каждую задачу можно решить бесконечным числом способов и нету какого-то универсального.
калькулятор считает размер скидки. есть 5 критериев. их можно взять и написать один за другим. надо выкинуть 3й и добавить новый — изучаем всю логику и режем кусочки, или не лезем в логику рассчетов, а удаляем в конструкторе подключение 3-го и пишем еще один. конечно, не всегда можно найти 5 обособленных критериев.
фотогалерея уже нашлась в комментах, см. выше.
система сообщений между пользователями на сайте может отображать кол-во новых сообщений в статус баре, и когда понадобится добавить алерт о новом сообщении, мы сможем сделать это быстро, а когда понадобится его удалить, не будет никаких сомнений в работоспособности системы. хотя, имхо, тут лучше наблюдатель задействовать :)
повторюсь, я не призываю юзать декоратор везде, а только там, где это действительно профитно.
и вот когда я до неё додумался :) понял профитность реализации «как написано», а не как умею.
вы не дочитали всего-навсего реализацию на JS с очень незначительными вариациями от классики, в отличие от множества других примеров декоратора когда «работоспособность остается», а профит от подхода много меньше.