有些代码可能会说一千多个单词:
/**
* Represents an amount of a resource
* @param {number} amount
* @param {string} type
*/
function Resource(amount, type)
{
var nAmount = amount;
var sType = type;
if (amount < 0)
{
throw new IllegalArgumentException("amount has to be positive");
}
/**
* @method Resource
* @return {number} amount of the resource
*/
this.getAmount = function()
{
return nAmount;
};
/**
* @method Resource
* @return {string} resource type
*/
this.getType = function()
{
return sType;
};
}
/**
* Addition of two resources produces a new resource with the sum amount
* the new object uses the old one as prototype
* @param {Resource} resource
* @return {Resource} new Resource object
*/
Resource.prototype.plus = function(resource)
{
if (!(resource instanceof Resource && this.getType() == resource.getType()))
{
throw new IllegalArgumentException("resources don't match.");
}
var newRes = Object.create(this); // create a new object based on the current one
// execute the Resource constructor on it
Resource.call(newRes, this.getAmount() + resource.getAmount(), this.getType());
return newRes;
};
资源对象是被认为是不可变的值对象。它们在加法操作中返回一个新对象。现在,我不只是调用“new Resource(args)”来创建要返回的新对象,而是基于旧对象创建了一个新对象。这也允许继承。
当我开始在我所有的 ValueObjects 上使用它时(以防我将来想从它们继承),我开始更多地考虑这个问题。
JavaScript 不允许不可变对象。然而,通过直接方法覆盖或调用其构造函数,对象很容易受到攻击。我所能做的就是确定这些是坏习惯。不幸的是,ECMAScript5“冻结”还没有出现,尽管我的模式与它兼容。
既然我有这种在不可变对象上调用构造函数以及代码重复的“坏风格”,我正在考虑创建一个新函数来封装这个过程:
Object.recreate = function(proto, constructor, args)
{
var obj = Object.create(proto);
constructor.apply(obj, args);
return obj;
};
因此:
Resource.prototype.plus = function(resource)
{
// if ... {throw ...}
return Object.recreate(this, Resource,
[this.getAmount() + resource.getAmount(), this.getType()]);
};
也许有人对这个函数的名称有更好的想法。“重建”是我的第一个想法。您如何看待这种模式?是不是过于抽象了?我应该把它保存到我确定会继承的类吗?我错过了什么重要的事情吗?
编辑:我看到我忘了提到一些重要的东西,目前在这篇文章中没有反映出来。使用 Object.create 可以轻松克隆 ValueObject。他们的私人成员是不变的。但是可变的私人成员呢?如果在克隆上调用 set(),它将在闭包中设置原始原型对象!当我的 Object.recreate 重新创建闭包时,这个问题就解决了。
那么有没有更好的方法来继承私有变量呢?为什么每个人都使用糖来创建课程?我已经阅读了很多关于原型主义的内容,但我仍然没有掌握它的窍门。