5

寄生构造器模式可以看作是工厂模式和构造器模式的结合。在工厂模式中,我们调用一个函数,该函数显式地创建一个对象并向该对象添加所需的属性和方法,最后返回该对象。

function createPerson(name, age, job){
    var o = new Object();   //explicit object creation
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
            alert(this.name);
        };
    return o;
}

var person1 = createPerson(“Nicholas”, 29, “Software Engineer”);
var person2 = createPerson(“Greg”, 27, “Doctor”);

注意事项:

  • 创建并返回显式对象
  • 方法和属性被添加到显式创建的对象
  • 方法在没有new操作符的情况下被调用

缺点:它不允许识别对象的类型。

任何函数都可以通过使用运算符调用它来视为构造函数new。在没有new操作符的情况下调用时,在函数内部,this对象指向全局对象(window在浏览器中)。并且当使用操作符调用该函数时new,它首先创建新的实例,object然后将this对象设置为新创建的对象。

构造函数模式将方法和属性添加到this对象并最终返回this对象,从而允许稍后使用instanceOf运算符识别对象的类型。

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
            alert(this.name);
        };
    }

    var person1 = new Person(“Nicholas”, 29, “Software Engineer”);
    var person2 = new Person(“Greg”, 27, “Doctor”);

注意事项:

  • 使用操作符调用函数new(使 JavaScript 引擎将其视为构造函数)
  • 对象未显式创建,而是this返回对象

现在,寄生构造器模式显式地创建并返回一个类似于工厂模式的对象,并使用类似构造器模式的 new 运算符调用它:

function Person(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
            alert(this.name);
        };
    return o;
}

var friend = new Person(“Nicholas”, 29, “Software Engineer”);
friend.sayName(); //”Nicholas”

但是我看不到使用new运算符调用函数的用途。我的意思是,由于函数显式创建并返回对象,我们将无法使用instanceOf运算符显式识别对象类型。

那么寄生构造器模式有什么好处呢?是否有任何技术细节可以被利用或适用于特定的对象创建场景?或者只是创建对象的另一种可能的编程方法?

4

2 回答 2

3

我认为您在工厂中跳过的部分是,在大多数其他语言中,工厂要么会制造多种不同类型的相似对象,要么像这样:

var truck = carFactory("Truck");
var jeep  = carFactory("Jeep");

或这样做:

var piano = instrumentFactory.piano("Grand");
var bass  = instrumentFactory.bass("Upright");

或您希望它具有的任何其他界面...

或者工厂的职责是通过依赖注入和潜在的多态性从较小的类中创建一个非常大的类:

function createTank (gunType) {
    var armour = new Armour();
    armour.hp  = 120;

    var wheels = new ChainTracks();

    var driver = new Soldier();
    driver.hp  = 15;

    var gun = gunFactory(gunType);

    var tank = new Tank(armour, wheels, gun);
    tank.driver = driver;

    return tank; 
}

var ground_tank = createTank("cannon");
var aa_tank = createTank("flak_cannon");
var at_tank = createTank("depleted_uranium_lancer");

如果你有一个像创建一个对象、设置它的属性并返回对象一样简单的工厂,那么真的没有什么区别。

当您谈论使用许多专门的组件来组合某些东西(无论它们是注入的还是硬编码的),或者您正在处理继承时,这些差异就会发挥作用。

老实说,我建议更多地了解这些东西(对象组合和继承),然后再进一步研究不同的方法。

因为最终,如果您使用工厂,或者如果您使用修改通用对象的函数,或者如果您只是在代码中间使用了大量类,它最终不会对完成的代码产生任何影响。 .. 该程序将运行得很好,或者会死,不管你怎么切它。

它的不同之处在于您组织代码的方式以及编写代码的方式。
如果您所做的只是在页面上制作一个按钮,那么您实际上并不需要工厂。
如果您要在页面上制作功能齐全的 MP3 播放器,它需要 6 个按钮、一个播放列表、一个进度条以及一个显示曲目名称、艺术家姓名和封面艺术的显示...

...现在是开始研究工厂模式的好时机,以弄清楚如何将这些部件组合在一起,要求一件事,并让它从装配线上吐出成品。

于 2012-10-25T20:32:22.777 回答
1

我认为从你的角度来看没有太大的区别,但是如果你更进一步,实现抽象工厂模式,或者你开始多态你的工厂,你每次写一个新的都可以节省很多工作.

在 javascript 中,由于语言没有私有值,因此您可以为对象设置任何值,如果您使用支持对象的 OOP 标准的框架,工厂可以非常强大并从基类继承其大部分逻辑。

编辑

好的,在我看来,对于 JavaScript 和那些模式而言,最重要的一件事就是原型设计。

原型设计基本上是您在 javascript 中定义对象的方式,因此运行时实际上可以识别该对象并可以将其与其他对象区分开来。

基本上只使用原型看起来像这样:

var Person = function(name){
    this.name = name
}; //constructor
Person.prototype.constructor = Person;
Person.prototype.name = 'Dave';
Person.prototype.getName = function() {
    return this.name;
}

一些测试代码:

var dave = new Person('Dave');
console.log(dave.getName());​

最后是工厂:

var PersonFactory = function(name) {
    return new Person(name);
}

现在,该注释的问题通常是它的可维护性很差,并且它没有继承。

现在是大多数框架的功能:您可以创建帮助函数来构建原型,甚至构建原型链。基本上,您定义一个对象,该对象接受另一个对象,并将其他对象成员解析为所需类对象的原型,从而为继承等留下各种可能性。

一些例子可以在这里找到: http ://www.ruzee.com/blog/2008/12/javascript-inheritance-via-prototypes-and-closures

我喜欢 mootools 处理课程的方式:

var MyClass = new Class({
Extends: MyOtherClass
Implements: [MyInterface, MyOtherInterface],

myPublicValue: null,
myOtherValue: null,


initialize: function() {
    //constructor
},

doStuff: function() {
    return 'stuff done';
}

});

mootools 类系统本身的缺点: -Closure Compiler 不喜欢尾随逗号,您倾向于将它们留在代码中

-几乎没有IDE支持mootools类的自动完成(因为原型没有在文件中注释,可以使用脚本将您的类解析为原型文件)

现在有了这个,您可以进行大量的设计设计,让您的工厂从您自己的原型助手类继承,使用原型助手类来创建实际的工厂(这里有一些递归),您可以在创建时解析每个对象(延迟加载之类的)或在页面加载时解析每个类对象(小心,如​​果您进入继承,在它的大多数实现中,您派生的类必须首先解析)或任何可能的方式。

我希望这有所帮助:)

(对不起我现在英语不好,今晚我很累xD)

于 2012-10-25T08:54:58.493 回答