JavaScript 中的反向装饰器,或责任链





0/5 (0投票)
在 JavaScript 中实现责任链模式
引言
这是我对先前在其他两篇文章中涵盖主题的延续
本文中的代码可在 GitHub 上找到 这里。
实现了我称之为“反向装饰器”的东西。它实际上只是对责任链模式的一种变体。这是一种模块化编程风格,我相信它遵循 SOLID 原则。我已经在几个项目中使用了它,所有项目都在我的组织内部。我想听听其他人的看法。我将坚持使用一个简单的待办事项应用程序,以便将重点放在模式上。我将假设你已经阅读并理解了我的其他两篇文章,然后这只是 JavaScript 中的一个实现。
背景
我一直在研究装饰器模式一段时间了。我用 VB.NET 实现了它,因为那是我在工作中使用的语言。我写了我的第一篇 CodeProject 文章,其中包含装饰器模式和解释。接下来我写了反向装饰器文章,也包含解释。我想用 JavaScript 实现这个模式,因为该语言提供了一些优势。函数不必写在一个类中,dataObj
具有更大的灵活性,并且我们不需要实现接口。我不会重复我在其他两篇文章中涵盖的内容,主要是因为我只想发布这个示例。
起点
我们从一个 todo.html 文件开始。在 HTML 中,我创建了我们的待办事项应用程序的基本 UI。它引用了 Bootstrap CSS。没什么太令人兴奋的。我们将从两个 JavaScript 文件开始,以帮助我们组织项目。“todo.js” 文件是我们将在其中组合操作并运行它的地方。在“todoAdd.js” 中,我们将定义所有函数。我发现将函数与组合和运行分开进行维护更容易。
函数优先
我们将从函数文件“todoAdd.js” 开始。基本函数将具有此格式
function functionName(anyPramsHere, next){
return function(dataObj){
//function logic here
if(next){
next(dataObj);
}
};
}
这种格式将允许我们将函数组合在一起。使用 JavaScript 而不是 VB.NET 的一个好处是,我们不必声明一个类。我们可以只使用一个可以返回另一个函数的函数。“next
” 是下一个函数,dataObj
是将状态从一个函数传递到下一个函数的类。
对于这个简单的应用程序,我将使用五个函数。它们是
- 添加错误处理程序
- 从表单获取数据
- 将数据添加到表格
- 按到期日对表格进行排序
- 向用户显示任何错误
这些函数都不是特别突破性的,所以我们将完成它们,如下所示
//get the data from form
function getDataFromForm(next){
return function(dataObj){
if(!dataObj.hasError){
dataObj.dtAddDueDate = document.getElementById("dtAddDueDate").value;
dataObj.txtAddTask = document.getElementById("txtAddTask").value;
}
if(next){
next(dataObj);
}
};
}
//write it to the table
function addToTable(next){
return function(dataObj){
if(!dataObj.hasError){
var newRow = document.createElement("tr");
var ckCol = document.createElement("td");
var ck = document.createElement("input");
ck.type = "checkbox";
ckCol.appendChild(ck)
newRow.appendChild(ckCol);
var dtCol = document.createElement("td");
dtCol.innerText = dataObj.dtAddDueDate;
newRow.appendChild(dtCol);
var taskCol = document.createElement("td");
taskCol.innerText = dataObj.txtAddTask;
newRow.appendChild(taskCol);
var tblBody = document.getElementById("tblBody");
tblBody.appendChild(newRow);
}
if(next){
next(dataObj);
}
};
}
//sort the table on Due Date
function sortTableOnDueDate(next){
return function(dataObj){
var rows = document.getElementById("tblBody").rows;
var numSorted;
do {
numSorted = 0;
for (i = 0; i < rows.length; i++) {
var currEl = rows[i];
var nextEl = currEl.nextElementSibling;
if ((nextEl) &&
(new Date(currEl.cells[1].innerText) > new Date(nextEl.cells[1].innerText))) {
document.getElementById("tblBody").insertBefore(nextEl, currEl);
numSorted++;
}
}
} while (numSorted > 0);
if(next){
next(dataObj);
}
};
}
//add error handler
function addErrHandler(next) {
return function (dataObj) {
dataObj.err = {
hasError: false,
message: ""
}
try {
if (next) {
next(dataObj);
}
} catch (err) {
dataObj.err.hasError = true;
dataObj.err.message = err.message;
next(dataObj);
}
};
}
//show error to user
function showErrorToUser(next){
return function(dataObj){
if(dataObj.err.hasError){
alert("ERROR: " + dataObj.err.message);
}
if(next){
next(dataObj);
}
};
}
组合函数
在 todo.js 文件中,我们将把函数放在一起。我们反向组合它们,以便它们运行时会向前运行。我们这样做
var addToDo = function(){
// we compose here:
var runMe = null;
runMe = showErrorToUser(runMe);
runMe = sortTableOnDueDate(runMe);
runMe = addToTable(runMe);
runMe = getDataFromForm(runMe);
runMe = addErrHandler(runMe);
dataObj = {};
// run here:
runMe(dataObj);
};
反向组合并向前运行允许我们使用 async
/await
模式。如果你想知道为什么,请参阅我的 VB.NET 文章关于 反向装饰器。
在组合的末尾,我们创建 dataObj
。它将是我们从一个函数到另一个函数传递状态时持久化状态的地方。
运行它,它就可以工作了!
历史
- 2018 年 12 月 1 日:初始版本
- 2018 年 12 月 3 日:文章已更新