职责链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
该模式类似于调用原型方法一样:在该对象没有该方法时向上一个原型上寻找方法;该模式这是该方法无法处理这个请求时,用下一个方法处理该请求,这样形成一个链,每个方法都有可能被调用。
这里用一个表单验证做例子:
btn.addEventListener("click", function (event) {
if (input.value.length == 0) {
console.log("这里要输入东西");
} else {
if (Number.isNaN(+input.value)) {
console.log("这里是数字");
if (input.value.length < 3) {
console.log("这里要三个以上数字");
}
}
}
});
可以看到代码可读性很差,如果用职责链模式来重构:
function checkEmpty() {
if (input.value.length == 0) {
console.log("这里要输入东西");
}
return "next";
}
function checkNumber() {
if (Number.isNaN(+input.value)) {
console.log("这里是数字");
}
return "next";
}
function checkLength() {
if (input.value.length < 3) {
console.log("这里要三个以上数字");
}
return "next";
}
class Chain {
constructor(fn) {
this.checkRule = fn;
this.nextRule = null;
}
addRule(nextRule) {
this.nextRule = nextRule;
}
check() {
this.checkRule() == "next" ? this.nextRule.check() : null;
}
}
const isEmpty = new Chain(checkEmpty);
const isNumber = new Chain(checkNumber);
const isLength = new Chain(checkLength);
const check = new Chain(() => "next");
check.addRule(isEmpty);
isEmpty.addRule(isNumber);
isNumber.addRule(isLength);
isLength.addRule({ check: () => "end" });
btn.addEventListener("click", () => {
check.check();
});
现在代码可读性变强了,但是很明显变得相当庞大,并且每个链上的函数都得返回一个相同的“next”,这里用装饰模式稍微修改一下代码,做成链式调用:
function checkEmpty() {
if (input.value.length == 0) {
console.log("这里要输入东西");
}
}
function checkNumber() {
if (Number.isNaN(+input.value)) {
console.log("这里是数字");
}
}
function checkLength() {
if (input.value.length < 3) {
console.log("这里要三个以上数字");
}
}
class Chain {
constructor(fn) {
this.checkRule = fn ?? (() => "next");
this.nextRule = null;
}
addRule(nextRule) {
this.nextRule = new Chain(() => (nextRule(), "next"));
return this.nextRule;
}
end() {
this.nextRule = { check: () => "end" };
}
check() {
this.checkRule() == "next" ? this.nextRule.check() : null;
}
}
const checks = new Chain();
checks.addRule(checkEmpty).addRule(checkNumber).addRule(checkLength).end();
这样,代码的可读性更好,并且如果要在规则之间添加新规则,也只需要在调用链里新增而已:
function checkSum() {
const result = Array.prototype.reduce.call(
input.value,
(result, now) => {
return (result += +now);
},
0
);
if (result !== 10) {
console.log("和必须为10");
}
}
const checks = new Chain();
checks.addRule(checkEmpty).addRule(checkNumber).addRule(checkSum).addRule(checkLength).end();
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl
我经常迷上ruby的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情
这应该是一个简单的问题,但我找不到任何相关信息。给定一个Ruby中的正则表达式,对于每个匹配项,我需要检索匹配的模式$1、$2,但我还需要匹配位置。我知道=~运算符为我提供了第一个匹配项的位置,而string.scan(/regex/)为我提供了所有匹配模式。如果可能,我需要在同一步骤中获得两个结果。 最佳答案 MatchDatastring.scan(regex)do$1#Patternatfirstposition$2#Patternatsecondposition$~.offset(1)#Startingandendingpo
我想开始使用“Sinatra”框架进行编码,但我找不到该框架的“MVC”模式。是“MVC-Sinatra”模式或框架吗? 最佳答案 您可能想查看Padrino这是一个围绕Sinatra构建的框架,可为您的项目提供更“类似Rails”的感觉,但没有那么多隐藏的魔法。这是使用Sinatra可以做什么的一个很好的例子。虽然如果您需要开始使用这很好,但我个人建议您将它用作学习工具,以对您来说最有意义的方式使用Sinatra构建您自己的应用程序。写一些测试/期望,写一些代码,通过测试-重复:)至于ORM,你还应该结帐Sequel其中(imho
我开始了一个新的Rails3.2.5项目,Assets管道不再工作了。CSS和Javascript文件不再编译。这是尝试生成Assets时日志的输出:StartedGET"/assets/application.css?body=1"for127.0.0.1at2012-06-1623:59:11-0700Servedasset/application.css-200OK(0ms)[2012-06-1623:59:11]ERRORNoMethodError:undefinedmethod`each'fornil:NilClass/Users/greg/.rbenv/versions/1
rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http: