Comments 16
Пусть заклюют, не привыкать, но… всё это не CORE, всё это Фаулер…
+4
Поздравляю! Вы описали паттерн MVVM. Две модели — Balance и WinHandler — подписываются на события модели вида UI, и с помощью IoC дергают ее методы. Модель вида, в свою очередь, использует вид (jQuery) для отображения данных пользователю и получения от него обратной связи. Рекомендую посмотреть на AngularJS.
+2
Я описал принцип — сводить описание любой программерской задачи к двум паттернам, после чего их программировать будет очень легко. что получился MVVM, я не виноват )
Точно так же можно перегруппировать функциональность в соответствии с BDD, и получится такой же удобно структурированный код, но это уже не будет MVVM.
Точно так же можно перегруппировать функциональность в соответствии с BDD, и получится такой же удобно структурированный код, но это уже не будет MVVM.
0
Эм, я, похоже, что-то не понимаю, но вроде BDD и MVVM вообще из разных областей, BDD — подход к процессу разработки, а MVVM — к архитектуре, и одно другому не мешает совершенно. А про подходы и паттерны я ниже отписал — не надо придумывать новые термины для одной и той же сущности.
0
этот паттерн получился из подхода. если с таким же подходом проектировать другие вещи — будут получаться другие паттерны. так что, одно другому не мешает.
в общем, наверное я непонятно объяснил и в следующий раз объясню по-другому.
в общем, наверное я непонятно объяснил и в следующий раз объясню по-другому.
0
ну и, я говорю о подходе к процессу разработки как раз, а не об архитектуре. то есть ваше же сравнение с MVVM некорректно.
0
Статья у вас об архитектуре, про подход там ничего не сказано, вернее, сказано, что надо «просто описать то, что было в задаче» — и это прекрасно реализуется в примере, который «еще хуже», опровергая ваш же тезис, что «языки программирования не похожи на язык описания задач, которым мы пользуемся при постановке». А далее следует (безо всякого обяснения, почему так надо) описание реализации той же задачи с использованием переименованных MVVM + IoC. Я молчу про спорные моменты конкретной реализации, где обработчик событий знает об источнике, и сам подписывается на соответствующие события (что перечеркивает идею событий как таковую), request (реализация IoC?), не привносящие ничего по сравнению с вызовом метода конкретного объекта и пр.
0
Ну и про реализацию. Описанный диспетчер зависимостей легко реализуется парой функций subscribe и trigger:
Вот пример реализации той же задачи про монетки:
Тут также несложно добавить новый функционал:
или разделить UI на два объекта:
Можете объяснить, почему ваше решение лучше, и зачем нужен ваш фреймворк?
var handlers = {};
function subscribe(evt, handler) {
if (!handlers[evt]) handlers[evt] = [];
handlers[evt].push(handler);
}
function trigger(evt, data) {
if (handlers[evt]) {
handlers[evt].forEach(function(handler) { handler(data); });
}
}
Вот пример реализации той же задачи про монетки:
function Balance() {
this.balance = 0;
subscribe('UI.coinClicked', this.addCoins.bind(this));
}
Balance.prototype.addCoins = function() {
this.balance += 15;
trigger('Balance.changed', this.balance);
};
function WinWatcher() {
subscribe('Balance.changed', this.checkWin.bind(this));
}
WinWatcher.prototype.checkWin = function(balance) {
if (balance > 20) {
trigger('WinWatcher.userWins');
}
};
function UI() {
$('.coin').click(function() {
trigger('UI.coinClicked');
});
subscribe('WinWatcher.userWins', this.showWin.bind(this));
}
UI.prototype.showWin = function() {
$('.you_win').animate({opacity: 0});
};
subscribe('DOM.init', function () {
var ui = new UI(),
balance = new Balance(),
winWatcher = new WinWatcher();
});
Тут также несложно добавить новый функционал:
function GatherStat() {
subscribe('UI.coinClicked', this.sendClick.bind(this));
subscribe('WinWatcher.userWins', this.sendWin.bind(this));
}
GatherStat.prototype.sendClick = function() {
$.post('/stat/gather/ajax', {click: 1, date: new Date});
};
GatherStat.prototype.sendWin = function() {
$.post('/stat/gather/ajax', {win: 1, date: new Date});
};
или разделить UI на два объекта:
function UI() {
$('.coin').click(function() {
trigger('UI.coinClicked');
});
}
function UIWin() {
subscribe('WinWatcher.userWins', this.showWin.bind(this));
}
UI.prototype.showWin = function() {
$('.you_win').animate({opacity: 0});
};
Можете объяснить, почему ваше решение лучше, и зачем нужен ваш фреймворк?
0
объясню:
— посмотрите на ваши конструкторы. при усложнении задачи они станут монструозными и в одном месте будет слишком много знаний о разных задачах. это плохо
— рефакторинг в моей версии сводится к копи-пасте методов, в вашей — ещё и к переорганизации конструкторов. Это дополнительные минуты. зачем эта лишняя трата времени?
— в вашем случае код, относящийся к задаче (подписка на событие и обработка этого события), лежит в двух разных местах, что опять ведёт к трате времени при изучении кода. Зачем? Одна задача — один метод, зачем усложнять?
— в вашем случае события — это просто строки. об автодополнении средствами IDE можно забыть. в моём автодополнение есть.
— в вашем случае нужно сперва догадаться, что в задаче будет правильнее использовать события. в моём случае фреймворк и сама технология подталкивает к правильному решению.
— ваши конструкции вроде «this.showWin.bind» — это ещё одна зависимость от какого-то фреймворка. зачем? в моём случае решение полно и не требует внешних зависимостей, предоставляя полный и удобный стек.
И я не очень понимаю, почему, по-вашему, «спорные моменты конкретной реализации, где обработчик событий знает об источнике, и сам подписывается на соответствующие события (что перечеркивает идею событий как таковую)». В чём, по-вашему, идея событий и почему этот подход её перечёркивает?
— посмотрите на ваши конструкторы. при усложнении задачи они станут монструозными и в одном месте будет слишком много знаний о разных задачах. это плохо
— рефакторинг в моей версии сводится к копи-пасте методов, в вашей — ещё и к переорганизации конструкторов. Это дополнительные минуты. зачем эта лишняя трата времени?
— в вашем случае код, относящийся к задаче (подписка на событие и обработка этого события), лежит в двух разных местах, что опять ведёт к трате времени при изучении кода. Зачем? Одна задача — один метод, зачем усложнять?
— в вашем случае события — это просто строки. об автодополнении средствами IDE можно забыть. в моём автодополнение есть.
— в вашем случае нужно сперва догадаться, что в задаче будет правильнее использовать события. в моём случае фреймворк и сама технология подталкивает к правильному решению.
— ваши конструкции вроде «this.showWin.bind» — это ещё одна зависимость от какого-то фреймворка. зачем? в моём случае решение полно и не требует внешних зависимостей, предоставляя полный и удобный стек.
И я не очень понимаю, почему, по-вашему, «спорные моменты конкретной реализации, где обработчик событий знает об источнике, и сам подписывается на соответствующие события (что перечеркивает идею событий как таковую)». В чём, по-вашему, идея событий и почему этот подход её перечёркивает?
0
— посмотрите на ваши конструкторы. при усложнении задачи они станут монструозными и в одном месте будет слишком много знаний о разных задачах. это плохо
Не понял, почему при усложнении задачи мое решение должно стать монструознее вашей реализации? Пока 0:0.
— рефакторинг в моей версии сводится к копи-пасте методов, в вашей — ещё и к переорганизации конструкторов. Это дополнительные минуты. зачем эта лишняя трата времени?
Из реорганизации — перенос подписки на событие. В вашем случае, например, при выносе handleCoinClick надо будет перенести и EventPoint, а в моем случае только cut&paste метода, так что паритет, 1:1
— в вашем случае код, относящийся к задаче (подписка на событие и обработка этого события), лежит в двух разных местах, что опять ведёт к трате времени при изучении кода. Зачем? Одна задача — один метод, зачем усложнять?
В моем случае можно повесить один обработчик на несколько событий, и несколько обработчиков на одно, и это описание будет в одном месте, а не размазано по коду. Да и изучение такого кода обычно начинается с вопроса, кто обрабатывает то или иное событие, и в моем случае ответ очевиден после взгляда на конструктор, в вашем случае — надо пробежаться по всему коду, 2:1 в мою пользу.
— в вашем случае события — это просто строки. об автодополнении средствами IDE можно забыть. в моём автодополнение есть.
Про IDE — ну, разве что да. Но подобные архитектуры очень завязаны на схему событий, так что в любом случае одной IDE не обойтись, придется вести документацию и с ней сверяться, но ладно, 2:2.
— в вашем случае нужно сперва догадаться, что в задаче будет правильнее использовать события. в моём случае фреймворк и сама технология подталкивает к правильному решению.
В вашем тоже. В этой задаче самое главное — понять, что отображением данных должен заниматься один объект, обработкой баланса другой, а определением выигрыша — третий. Ваш подход показывает только их способ взаимодействия, а найти такой способ не так уж и сложно, что и было показано в моем примере. 2:2
— ваши конструкции вроде «this.showWin.bind» — это ещё одна зависимость от какого-то фреймворка. зачем? в моём случае решение полно и не требует внешних зависимостей, предоставляя полный и удобный стек.
Function.prototype.bind — стандартная функция ECMAScript5, частичное применение и указание контекста. Тут полностью работающее решение, из зависимостей только jQuery, и то не принципиально и легко вырезаемо, т. к. нужно только в UI (к тому же у вас jQuery тоже есть в зависимостях). Так что в моем решении на одну зависимость меньше, что явно лучше, 3:2
Итого, мое наколенное решение ничуть не хуже, а то даже и лучше (как минимум, отсутствием дополнительных зависимостей).
0
подтасовка оценок налицо :)
Речь шла о конструкторах,
Вот так будут выглядеть ваши конструкторы при мало-мальском усложнении задачи. Я не считаю это хорошим кодом, и уже пару раз объяснил, почему — в одном месте будет сосредоточено. После этого нам захочется подписку по условию — и всё, мы погрязли в лапше, нам нужен рефакториниг. Так что, 1:0.
угу, тот же copy-paste, что займёт не более пяти секунд у программиста в здравом уме и с незагипсованной рукой ))
Несколько событий на один обработчик можно и в моём случае, достаточно написать их через запятую
Несколько обработчиков на одно событие, описанных в одном месте — вот это как раз и противоречит концепции event-driven. Кстати, вы так и не объяснили, в чём, по-вашему, она заключается?
Несколько обработчиков на одно событие также противоречит концепции разделения обязанностей (ещё раз смотрим на конструкторы и убеждаемся, что конструктор «знает» слишком много).
Что же, ещё один балл в мою пользу
функции trigger и subscribe — это тоже зависимости, только наколенные. вы наверняка захотите их перенести в отдельный файл. так что это вообще не аргумент.
в итоге, моё решение-таки лучше, по вашим же аргументам и методике оценки =)
Не понял, почему при усложнении задачи мое решение должно стать монструознее вашей реализации?
Речь шла о конструкторах,
function AnyConstr(){
this.prop1 = 0;
this.prop2 = '';
......
subscribe('event1', this.method1.bind(this));
subscribe('event2', this.method2.bind(this));
subscribe('event3', this.method3.bind(this));
subscribe('event4', this.method4.bind(this));
subscribe('event4', this.method5.bind(this));
subscribe('event4', this.method6.bind(this));
.......
}
Вот так будут выглядеть ваши конструкторы при мало-мальском усложнении задачи. Я не считаю это хорошим кодом, и уже пару раз объяснил, почему — в одном месте будет сосредоточено. После этого нам захочется подписку по условию — и всё, мы погрязли в лапше, нам нужен рефакториниг. Так что, 1:0.
Из реорганизации — перенос подписки на событие. В вашем случае, например, при выносе handleCoinClick надо будет перенести и EventPoint, а в моем случае только cut&paste метода, так что паритет, 1:1
надо будет перенести и EventPoint
угу, тот же copy-paste, что займёт не более пяти секунд у программиста в здравом уме и с незагипсованной рукой ))
В моем случае можно повесить один обработчик на несколько событий, и несколько обработчиков на одно
Несколько событий на один обработчик можно и в моём случае, достаточно написать их через запятую
Core.CatchEvent(Event1, Event2, Event3, ...)
Несколько обработчиков на одно событие, описанных в одном месте — вот это как раз и противоречит концепции event-driven. Кстати, вы так и не объяснили, в чём, по-вашему, она заключается?
Несколько обработчиков на одно событие также противоречит концепции разделения обязанностей (ещё раз смотрим на конструкторы и убеждаемся, что конструктор «знает» слишком много).
Что же, ещё один балл в мою пользу
Так что в моем решении на одну зависимость меньше, что явно лучше, 3:2
функции trigger и subscribe — это тоже зависимости, только наколенные. вы наверняка захотите их перенести в отдельный файл. так что это вообще не аргумент.
в итоге, моё решение-таки лучше, по вашим же аргументам и методике оценки =)
0
Вот так будут выглядеть ваши конструкторы при мало-мальском усложнении задачи.
Это ни капли не хуже вашего кода. У вас будет ровно то же самое, но только еще с кодом метода-обработчика рядом.
var AnyConstr = {};
AnyConstr.Event1 = function () {
Core.CatchEvent(Some.Event1);
// ...
};
AnyConstr.Event2 = function () {
Core.CatchEvent(Some.Event2);
// ...
};
AnyConstr.Event3 = function () {
Core.CatchEvent(Some.Event3);
// ...
};
AnyConstr.Event4 = function () {
Core.CatchEvent(Some.Event4);
// ...
};
AnyConstr.Event5 = function () {
Core.CatchEvent(Some.Event5);
// ...
};
AnyConstr.Event6 = function () {
Core.CatchEvent(Some.Event6);
// ...
};
При этом значительно сложнее понять без детального изучения кода, какие события у нас обрабатываются и чем. С упомянутой вами подпиской по условию это вообще будет ад и израиль. Так что именно такой вариант я бы не назвал хорошим кодом.
угу, тот же copy-paste, что займёт не более пяти секунд у программиста в здравом уме и с незагипсованной рукой ))
В моем варианте это займет не больше.
Несколько обработчиков на одно событие, описанных в одном месте — вот это как раз и противоречит концепции event-driven.
Лолшто? В событиях как раз и ценно то, что обработчиков у одного события может быть сколько угодно. Иначе можно обойтись просто коллбэками. Про противоречие нескольких обработчиков одного события концепции разделения обязанностей — это вообще пушка, там как раз наоборот все, несколько событий один обработчик не должен обрабатывать.
функции trigger и subscribe — это тоже зависимости,
Только раз в двадцать меньше, без парсинга исходников и понятные любому программисту.
В итоге имеем отличие от моего решения максимум во внешнем виде кода (и то спорном), и это ценой дополнительных 7кб.
0
ну и то, что вы называете минусом («обработчик событий знает об источнике») — это, наоборот, плюс — это его обязанность знать об источнике и о том, что он из источника получит. иначе придется где-то ещё описывать связь с источником — лишнее усложнение (что у вас закономерно в конструкторах и получилось)
0
Чем больше в интернете разных подходов описать одну и ту же проблему — тем проще новичкам будет учиться.
Задача опытных девелоперов тут — не допустить в статьях откровенных ошибок в решении проблемы.
и да, хорошо если в решении будут линки на хрестоматийную литературу
p.s. сори чет не прикрепилось куда надо, это ответ для maxatwork
Задача опытных девелоперов тут — не допустить в статьях откровенных ошибок в решении проблемы.
и да, хорошо если в решении будут линки на хрестоматийную литературу
p.s. сори чет не прикрепилось куда надо, это ответ для maxatwork
0
Sign up to leave a comment.
Articles
Change theme settings
Технология CORE