Kyle Simpson的“OLOO(链接到其他对象的对象)模式”与原型设计模式有什么不同吗?除了通过专门指示“链接”(原型的行为)并澄清这里没有“复制”发生(类的行为)来创造它之外,他的模式究竟引入了什么?
这是凯尔的模式的一个例子,来自他的书《你不知道JS:这个》
var Foo = {
init: function(who) {
this.me = who;
},
identify: function() {
return "I am " + this.me;
}
};
var Bar = Object.create(Foo);
Bar.speak = function() {
alert("Hello, " + this.identify() + ".");
};
var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2");
b1.speak(); // alerts: "Hello, I am b1."
b2.speak(); // alerts: "Hello, I am b2."
“你不知道JS:这个”中的讨论
1
当一个“类”在经典模式中“继承”另一个“类”时,两个函数可以用类似的语法声明(“函数声明”或“函数语句”):
function Point(x,y) {
this.x = x;
this.y = y;
};
function Point3D(x,y,z) {
Point.call(this, x,y);
this.z = z;
};
Point3D.prototype = Object.create(Point.prototype);
相反,在OLOO模式中,不同的语法形式用于定义基本对象和派生对象:
var Point = {
init : function(x,y) {
this.x = x;
this.y = y;
}
};
var Point3D = Object.create(Point);
Point3D.init = function(x,y,z) {
Point.init.call(this, x, y);
this.z = z;
};
正如你在上面的例子中看到的,基本对象可以用对象文字符号定义,而相同的符号不能用于派生对象。这种不对称困扰着我。
2
在OLOO模式中,创建对象有两个步骤:
>
调用一些自定义的非标准方法来初始化对象(您必须记住这一点,因为它可能因对象而异):
var p2a = Object.create(Point);
p2a.init(1,1);
相反,在原型模式中,您使用标准操作符< code>new:
var p2a = new Point(1,1);
3.
在经典模式中,我可以通过将“静态”效用函数直接分配给“类”函数(与其<代码>相反),来创建不直接应用于“即时”的“静态”效用函数。原型)。例如,类似于下面代码中的函数< code>square:
Point.square = function(x) {return x*x;};
Point.prototype.length = function() {
return Math.sqrt(Point.square(this.x)+Point.square(this.y));
};
相反,在OLOO模式中,对象实例上也可以使用任何“静态”函数(通过[[原型]]链):
var Point = {
init : function(x,y) {
this.x = x;
this.y = y;
},
square: function(x) {return x*x;},
length: function() {return Math.sqrt(Point.square(this.x)+Point.square(this.y));}
};
我读了凯尔的书,我发现它非常有信息,尤其是关于这个
是如何绑定的细节。
对我来说,OLOO有两大优点:
OLOO 依靠 Object.create()
创建一个新对象,该对象 [[prototype]]
链接到另一个对象。您不必了解函数具有原型
属性,也不必担心其修改带来的任何潜在的相关陷阱。
这是有争议的,但我觉得OLOO语法(在许多情况下)比“标准”javascript方法更简洁,尤其是在多态(超级
风格的调用)方面。
我认为设计中有一点值得怀疑(实际上有助于上述第2点),那就是阴影:
在行为委托中,我们尽可能避免在< code>[[Prototype]]链的不同层次上对事物进行相同的命名。
这背后的想法是,对象有自己更具体的功能,然后在内部委托给链上更低的功能。例如,您可能有一个带有< code>save()函数的< code>resource对象,该函数将对象的JSON版本发送到服务器,但您也可能有一个带有< code>stripAndSave()函数的< code>clientResource对象,该函数首先删除不应发送到服务器的属性。
潜在的问题是:如果其他人出现并决定制作一个特殊的资源
对象,而不完全了解整个原型链,他们可能会合理地*决定在名为 save
的属性下保存最后一次保存的时间戳,该属性在原型链的两个链接下隐藏了资源
对象上的基本 save()
功能:
var resource = {
save: function () {
console.log('Saving');
}
};
var clientResource = Object.create(resource);
clientResource.stripAndSave = function () {
// Do something else, then delegate
console.log('Stripping unwanted properties');
this.save();
};
var specialResource = Object.create( clientResource );
specialResource.timeStampedSave = function () {
// Set the timestamp of the last save
this.save = Date.now();
this.stripAndSave();
};
a = Object.create(clientResource);
b = Object.create(specialResource);
a.stripAndSave(); // "Stripping unwanted properties" & "Saving".
b.timeStampedSave(); // Error!
这是一个特别人为的例子,但关键是,特别是不遮蔽其他属性会导致一些尴尬的情况和大量使用同义词库!
也许一个更好的例子是<code>init</code>方法——特别是当OOLO绕过构造函数类型函数时。由于每个相关对象都可能需要这样一个函数,因此适当地命名它们可能是一项繁琐的工作,而唯一性可能会让人难以记住要使用哪一个。
*实际上它不是特别合理(lastSaved
会更好,但这只是一个例子。)
他的模式到底介绍了什么?
OLOO接受原样的原型链,而不需要在其他(IMO混淆的)语义上进行分层来获得链接。
因此,这两个片段的结果完全相同,但实现方式不同。
构造函数形式:
function Foo() {}
Foo.prototype.y = 11;
function Bar() {}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.z = 31;
var x = new Bar();
x.y + x.z; // 42
OLOO表格:
var FooObj = { y: 11 };
var BarObj = Object.create(FooObj);
BarObj.z = 31;
var x = Object.create(BarObj);
x.y + x.z; // 42
在这两个代码段中,< code>x对象链接到一个对象(< code>Bar.prototype或< code>BarObj),该对象又链接到第三个对象(< code>Foo.prototype或< code>FooObj)。
代码段之间的关系和委派是相同的。代码段之间的内存使用情况相同。创建许多“子对象”(即许多对象,如 x1
到 x1000
等)的能力在代码片段之间是相同的。代码段之间的委派(x.y
和 x.z
)的性能相同。使用 OLOO 的对象创建性能较慢,但健全性检查显示性能较慢实际上不是问题。
我认为OLOO提供的是,只表达对象并直接链接它们要比通过构造函数/new
机制间接链接它们简单得多。后者假装是关于类的,但实际上只是一个表达委托的可怕语法(附注:ES6 class
语法也是如此!).
OLOO只是避开了中间人。
这是class
与OLOO的另一个比较。
6. 原型模式(Prototype) Intent 使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。 Class Diagram Implementation // java public abstract class Prototype { abstract Prototype myClone(); } // java public class ConcreteProt
介绍 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象。 正文 对于原型模式,我们可以利用JavaScript特有的原型继承特性去创建对象的方式,也就是创建的一个对象作为另外一个对象的prototype属性值。原型对象本身就是有效地利用了每个构造器创建的对象,例如,如果一个构造函数的原型包含了一个name属性(见后面的例子),那通过这个构造函数创建的
主要内容:1.GRASP:通用职责分配软件模式(共9种),2.SOLID:设计原则(共5种),3.GOF:设计模式(共23种),4.其他必要设计原则GRASP: 通用职责分配软件模式(共9种) SOLID:设计原则(共5种) GOF:设计模式(共23种) 其他必要设计原则 1.GRASP:通用职责分配软件模式(共9种) 告诉我们怎样设计问题空间中的类与分配它们的行为职责,以及明确类之间的相互关系等 Infomation Expert(信息专家) Creator(创造者) Low coupling
本文向大家介绍Java设计模式之Prototype原型模式,包括了Java设计模式之Prototype原型模式的使用技巧和注意事项,需要的朋友参考一下 一、场景描述 创建型模式中,从工厂方法模式,抽象工厂模式,到建造者模式,再到原型模式,我的理解是,创建对象的方式逐步从编码实现转向内存对象处理。 例如,在“仪器数据采集器”的子类/对象“PDF文件数据采集器”和“Excel文件数据采集器”的创建过程
本文向大家介绍JavaScript设计模式之原型模式分析【ES5与ES6】,包括了JavaScript设计模式之原型模式分析【ES5与ES6】的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了JavaScript设计模式之原型模式。分享给大家供大家参考,具体如下: 从设计模式的角度讲,原型模式是用于创建对象的一种模式,若需要创建一个对象,一种方法是先指定其类型,然后通过类来创建这个对象,另一
本文向大家介绍JavaScript设计模式之原型模式(Object.create与prototype)介绍,包括了JavaScript设计模式之原型模式(Object.create与prototype)介绍的使用技巧和注意事项,需要的朋友参考一下 原型模式说明 说明:使用原型实例来 拷贝 创建新的可定制的对象;新建的对象,不需要知道原对象创建的具体过程; 过程:Prototype => new P