来自Java,我想知道Java最佳实践是否适用于JavaScript。
在Java中,接口和实现是分离的,将它们混合起来被认为是一种不好的做法。出于同样的原因,建议从最终开发人员隐藏库的实现细节。
例如,log4J是最受欢迎的日志库之一,但建议将代码写入slf4j库或“包装”log4j的Commons Logging库。这样,如果您选择切换到另一个日志记录框架(如logback),则可以在不更改代码的情况下执行此操作。另一个原因是,作为日志库的用户,只要您知道日志记录的作用,您就不会担心如何进行日志记录。
回到JavaScript,大多数非平凡的Web应用程序都有自己的自定义JavaScript库,其中许多使用开源库,如jQuery和dojo。如果自定义库依赖于jQuery,而不是作为扩展,而是作为实现,您是否认为需要添加另一个包装jQuery的层并使其对其余JavaScript代码透明?
例如,如果您拥有包含所有自定义前端逻辑的foo库,那么您将引入仅包装jQuery的bar库。这样,你的foo库就会使用bar库来实现jQuery函数,但它完全没有jQuery。从理论上讲,您可以切换到其他库,例如dojo和google web toolkit,而不会对foo库产生太大影响。
你认为这有什么实际价值吗?矫枉过正?
答案 0 :(得分:15)
虽然从理论的角度来看它是有道理的,但在实践中我会说它太过分了。如果出于以下两个原因没有别的:
答案 1 :(得分:6)
根据我的经验并且自己也是一名Java开发人员,有时候我们倾向于将整个“抽象”层模式过分考虑,我已经看到有人为了“灵活性”而决定完全抽象某个框架的实现但最终会使事情变得更复杂,并且需要创建更多代码来维护。
底线是您应该根据具体情况来看一下,例如,您不会尝试在struts之上或JPA之上创建一个抽象层,以防万一然后再去另外一个框架(我很少见到)。
我的建议是,无论您使用何种框架,创建在内部使用框架的对象和组件,他们都应该为您的问题建模并能够在不需要任何特定框架的情况下进行交互。
希望这有帮助。
答案 2 :(得分:5)
这里有很多好的答案,但我没有看到的一件事就是功能集。如果您尝试编写一个库来包装jQuery提供的功能,但是您希望能够轻松换出类似原型的东西,则会遇到问题。 jQuery库没有提供原型提供的所有功能,而原型也没有提供jQuery提供的所有功能。最重要的是,它们都以完全不同的方式提供它们的功能(原型扩展了基础对象 - 这几乎不可能包装)。
最后,如果你试图将这些库包装在一些增加“抽象”的代码中以试图使它们更加灵活,那么你将失去80%的框架所提供的内容。你将失去他们提供的花哨界面(jQuery提供了一个很棒的$('选择器')函数,原型扩展了基础对象),你还必须决定是否要省略功能。如果两个框架都没有提供给定的功能,您必须抛弃它或为其他框架重新实现它。这是一大堆蠕虫。
整个问题源于Java是一种非常不灵活的语言。库提供了功能,就是这样。在JavaScript中,语言本身非常灵活,可以让你做很多疯狂的事情(比如编写一个库,并将它分配给$
变量)。做疯狂事情的能力让javascript库的开发人员提供了一些非常有创意的功能,但这意味着你不仅可以在库中找到共性并编写抽象。我认为编写好的JavaScript需要对Java开发人员进行重大改变。
答案 3 :(得分:2)
有人曾经说过“过早优化是所有邪恶的根源。”我相信这适用于这种情况。
正如其他人所表达的那样,在你真正需要抽象之前,你不想为了灵活性而抽象。否则,您最终会做更多不必要的工作,并在需要之前引入不必要的复杂性。这需要花钱,实际上会使您的代码更加脆弱。
此外,如果您的代码组织良好且经过充分测试,您不应该害怕重大变化。代码总是在变化,尝试预测和优化可能会或可能不会发生的变化几乎总会让您遇到麻烦而不是拯救您。
致谢:我应该赞扬敏捷编程以及我对该主题的实践和阅读。我所说的直接来自于我对敏捷的理解,我发现它是一个非常好的剃刀,可以减少我工作的额外成本并完成很多工作。此外,我所说的一切都不是特定于JavaScript的......我会以任何语言应用这些原则。
答案 4 :(得分:2)
有很好的论据称这种开发实践 - 包装以便以后切换 - 用任何语言提问。
Oren Eini的一句好话,来自他的writeup on wrapping ORMs:
尝试封装制作东西 更容易使用,很棒。尝试去 封装,以便您可以切换 OR /小姐?不会工作,将是昂贵的 痛苦。
答案 5 :(得分:1)
这绝对是在企业环境中完成的事情。
以一家拥有自己的自定义javascript框架的公司为例,该框架用于所有项目。每个项目都决定使用自己的框架(jQuery,Dojo,Prototype)来为公司框架的底层模块添加功能。在项目之间移动的员工现在可以很容易地这样做,因为他们使用项目代码库的API仍然是相同的,即使每个项目的底层实现可能不同。抽象在这些情况下很有用。
答案 6 :(得分:1)
这太过分了。 Javascript不是Java,与Java没有任何关系。这是一种完全不同的语言,出于营销原因,它在名称中得到了J-a-v-a。
如果您关心附加库的可用性,那么选择具有大型生态系统的框架。在企业环境中,您将通过标准化现成的非自定义Web框架来进一步领先,您可以每年升级,跟踪世界其他地方。然后用一个SMALL内部附加库来补充它,当然,你必须自己维护,更不用说培训你雇用的任何新程序员了。
由于您在客户端(Web浏览器)中讨论Javascript,因此限制人们使用它进行操作的复杂性更为重要。不要构建大量的客户端代码,也不要制造那么脆弱的东西,而另一个程序员则无法维护它。 Web框架可以帮助您减少行数,并使您自己的代码保持相当简单。
这不是Javascript最佳实践的问题,因为对于服务器端的JS,例如Rhino或node.js,这会有所不同。
答案 7 :(得分:1)
在这种情况下,适配器模式不是常见的解决方案。我知道使用此模式的唯一示例是extjs。 Javascript项目通常太小,并且通过创建这样的抽象层不值得你做的努力。 此问题的常见解决方案是您尝试将多个框架一起使用,例如jquery.noConflict。
答案 8 :(得分:1)
我以前做过这个,并且可以谈谈编写库/工具包包装的经验。
计划是从Prototype转移到其他图书馆。 Dojo是第一选择,但当时我不确定这是否是将所有内容移动到的库(以及我所说的所有内容~5MB的Prototype-happy JS)。所以来自一个干净的界面世界,我准备在Prototype和Dojo周围写一个;如果事实上这是必要的话,一个令人敬畏的界面可以轻而易举地从dojo切换出来。
这是一个错误,由于一些原因需要花费大量的时间和精力。第一个是虽然两个库可以提供相同的功能,但是(a)它们的API几乎总是不同的,最重要的是(b)你用一个库编程的方式会有所不同。
为了演示,让我们采取像添加类名一样常见的东西:
// Prototype
$("target").addClassName('highlighted');
// Dojo
dojo.addClass("target", "highlighted");
// jQuery
$("target").addClass("highlighted");
// MooTools
$('target').set('class', 'highlighted');
到目前为止非常直截了当。让我们稍微复杂一点:
// Prototype
Element.addClassName('target', 'highlighted selected');
// Dojo
dojo.addClass("target", ["highlighted", "selected"]);
// jQuery
$("target").addClass(function() {
return 'highlighted selected';
});
// MooTools
$("target").set({
"class": "highlighted selected"
});
现在为您的addClass版本选择一个接口后,您有两个选择:(1)代码到最小公分母,或(2)实现库的所有非交叉功能。
如果你选择第一名 - 你将失去每个图书馆的“个性”/最佳品质。如果你选择#2 - 你的addClass代码将比任何库提供的代码大4倍,因为例如当包含Dojo时,你必须编写函数的代码作为第一个param(jQuery)和Object作为第一个参数(MooTools)。
因此,虽然它在理论上是可行的,但它不实用,但却是了解那些库的复杂性的一种非常好的方法。