Javascript装饰器模式-原型或单个函数
Javascript Decorator Pattern - Prototype or single function?
我正在浏览Addy Osmani关于装饰图案的教程(点击此处http://addyosmani.com/blog/decorator-pattern/)我对如何在Javascript中实现最简单的Decorator有点困惑。似乎有些示例使用obj.prototype模式向现有对象添加功能,有些示例创建独立函数并传递对象。
// Decorator Pattern ?
function coffee(size, flavors) {
this._size = size || "medium";
this._flavors = flavors || [];
this._cost = 100;
this.info = function() {
console.log(this._size, this._flavors, this._cost);
}
}
// Decorator - Would this be considered a decorator since the functionality needed to add flavors default to the coffee object?
function addFlavor(coffee, flavor) {
coffee._flavors.push(flavor);
coffee._cost = coffee._cost + 25;
}
// Decorator - Engrave the cup? lol
function engraving(coffee) {
coffee._cost = coffee._cost + 200;
}
// Decorator Variation w/ prototype instead - Add cream
coffee.prototype.addCream = function () {
this._cost = this._cost + 100;
};
// Instantiate Coffee
testCoffee = new coffee('Large', ['vanilla']);
// Add Flavors
addFlavor(testCoffee, 'chocolate');
addFlavor(testCoffee, 'almond');
addFlavor(testCoffee, 'hazelnut');
// Add Engraving
engraving(testCoffee);
// Add Cream
testCoffee.addCream();
// Log it all to the console
testCoffee.info();
这个例子的JsFiddle可以在这里找到:http://jsfiddle.net/pathsofdesign/ocbbzoy2/
我的问题是:看起来我可以使用原型继承来实现Decorator模式。这样做(即:我的addCream()方法)有什么优点或缺点吗?谢谢
更新:
看起来我的示例根本没有实现Decorator模式。Etai和Bergi在下面给出了很好的答案。如果我理解正确的话,传统的JS Decorator"包装"另一个对象,然后在不修改基础对象的情况下对该特定对象的行为进行调整。
否。你所拥有的不是装饰器,它们只是方法。方法确实会使对象发生变异,装饰器通过覆盖方法使行为发生变异。它们与mixins非常相似,只是它们不创建新方法。
例如,让我们给Coffee
类一个setSize
方法:
Coffee.prototype.setSize = function(size) {
this._size = size || 'medium';
};
现在,让我们来找一个比例不对的疯狂咖啡师:
function extreme(coffee) {
var oldMethod = coffee.setSize;
coffee.setSize = function(size) {
oldMethod.call(this, size && 'Xtra'+size[0].toUpperCase()+size.slice(1));
};
}
并让他提供一个被订购为"大"的:
> var coffee = extreme(new Coffee);
> coffee.setSize("large")
> coffee.info()
XtraLarge, Array [], 100
我觉得这个教程很混乱。
假设你想创建一个simpleItem作为你的基本项,以及一个complexItem,它是你的simpleItem加上更多。
使用原型继承:
function SimpleItem(name){
this.name = name;
}
function ComplexItem(size){
this.size = size;
}
ComplexItem.prototype = new SimpleItem('complex');
var item = new ComplexItem(3); //{size: 3, name: 'complex'}
ComplexItem.prototype.name = 'new complex name'; //item is now {size: 3, name: 'new complex name'}
使用装饰器模式:
function SimpleItem(name){
this.name = name;
}
function ComplexItem(size){
SimpleItem.call(this, 'complex');
this.size = size;
}
var item = new ComplexItem(3); //{size: 3, name: 'complex'}
ComplexItem.prototype.name = 'new complex name'; //item is still {size: 3, name: 'complex'}
虽然看起来ComplexItem继承自SimpleItem,但实际上并不是。它被它装饰着。这真的和做这个一样:
function decorateMe(name){
this.name = name;
}
function ComplexItem(size){
decorateMe.call(this, 'complex');
this.size = size;
}
这允许类似于"多重继承"的操作,但以后更改父对象中的某些内容不会影响已经创建的子对象。
一般来说,decorator模式意味着你通过执行一些会改变实例的代码来"装饰"实例
编辑:请注意,尽管我使用这个例子来装饰属性,正如@Bergi所指出的,装饰器实际上是用来装饰行为(功能)的@Bergi的答案实际上是经典的装饰模式,即用新方法包裹旧方法,从而"装饰"它。我的例子更多的是一个mixin/extend模式。然而,该模式的主要思想是在运行时对其进行更改,而不是从另一个原型继承。
- 使用“;这个“;JavaScript原型方法中的关键字
- Javascript,有没有一种方法可以将数组写成没有逗号或空格的单个文本字符串
- 如何使用javascript获取嵌套对象中所有子对象的单个属性
- 是否可以禁用jquery中的单个单选按钮
- 引用类变量中的原型方法
- 引导程序:在导航栏中,显示悬停在单个位置的基于Li Link的不同内容
- 如何从对象的原型方法访问JavaScript对象属性
- 为什么要包装每一个原型“;类“;JS中具有匿名函数的对象
- 使用jquery选中/取消选中单个复选框
- Node.js中的JavaScript原型对象效率
- 单个页面上有多个标记表单
- 在不破坏未定义函数的情况下,对多个视图使用单个js文件
- 用于多个类事件Jquery的单个函数
- 重载JS'firefox中的对象原型
- 仅使用文件对象选择单个文件
- 在JavaScript中,如何使用单个“”从子类中的父类继承;.原型;块
- 如何使用exports或module.exports将函数构造函数对象方法与原型封装在单个模块中
- Javascript装饰器模式-原型或单个函数
- 在JavaScript实例上编写单个原型和使用多个原型之间的区别?只是风格
- 单个脚本文件中的两个原型引发了这个问题