【问题标题】:Javascript diamond inheritance structureJavascript菱形继承结构
【发布时间】:2013-05-13 16:26:09
【问题描述】:

使用节点但在 JavaScript 中寻找钻石继承的方法:

var util = require('util');

function Base(example_value) {
  console.log(example_value);
  this.example_property = example_value;
  this.example_method = function() { ... };
}

function Foo(settings) {
  var f = settings.f;
  Base.call(x);
  this.settings = settings;
}

util.inherits(Foo, Base);

function Bar(settings) {
  var b = settings.b;
  Base.call(b);
  this.settings = settings;
}

util.inherits(Bar, Base);

var foo = new Foo({f: 'bar'});
// 'bar' gets printed and I can call methods from Base..
foo.example_method();
var bar = new Bar({b: 'foo'});
// 'foo' gets printed and I can call methods from Base..
bar.example_method();

这里没有问题..但是我需要在另一个包罗万象的对象中制作 Foo 和 Bar(和 Base)中可用的所有内容:

function Top(settings) {
  Foo.call(this, settings);
  Bar.call(this, settings);
}

util.inherits(Top, Foo);
util.inhertis(Top, Bar);

var top = new Top({some: 'value'});

'value' 被打印两次,这不是我想要的。像这样进行继承可能不是最好的方法,因此寻找替代方案/建议来处理这种菱形结构。

附:没有包含原始代码,但经过修改以希望简化 - 我是手工完成的,不认为有任何错误,但我试图理解的重点应该在那里。

【问题讨论】:

  • 我根本看不到“value”是如何打印的,因为“settings”对象既没有“f”也没有“b”属性。
  • @Pointy: fb 在构造函数参数中设置(例如var foo = new Foo({f: 'bar'});)。
  • @Cory 是的,并且函数“Top”是使用具有名为“some”的单个属性的对象调用的。 “Top”函数传递它传递给“Foo”和“Bar”的对象。
  • @Pointy:好的,我明白了。鉴于“'value' 被打印两次”,我认为示例代码是错误的。
  • 抱歉,example_value 被打印了两次。感谢您选择此内容

标签: javascript inheritance


【解决方案1】:

你可以使用委托吗?

function Top(settings) {
  this.foo = new Foo(settings);
  this.bar = new Bar(settings);
}

Top.prototype.conflictingMethod = function() {
   // use either this.foo or this.bar
}
Top.prototype.anotherMethod = function() {
   return this.foo.anotherMethod();
}

你也可以使用 mixins,但你需要将它添加到你的类系统中。 Ext-JS 支持 mixins http://www.sencha.com/learn/sencha-class-system

// My/sample/CanSing.js
Ext.define('My.sample.CanSing', {
    sing: function(songName) {
        alert("I'm singing " + songName);
    }
});

// My/sample/CanPlayGuitar.js
Ext.define('My.sample.CanPlayGuitar', {
    playGuitar: function() {
        alert("I'm playing guitar");
    }
});

// My/sample/CanComposeSongs.js
Ext.define('My.sample.CanComposeSongs', {
    composeSongs: function() {
        alert("I'm composing songs");

        return this;
    }
});

// My/sample/CoolGuy.js
Ext.define('My.sample.CoolGuy', {
    extend: 'My.sample.Person',
    mixins: {
        canSing: 'My.sample.CanSing',
        canPlayGuitar: 'My.sample.CanPlayGuitar'
    }
});

// My/sample/Musician.js
Ext.define('My.sample.Musician', {
    extend: 'My.sample.Person',
    mixins: {
        canSing: 'My.sample.CanSing',
        canPlayGuitar: 'My.sample.CanPlayGuitar',
        canComposeSongs: 'My.sample.CanComposeSongs'
    }
});

// app.js
var nicolas = new My.sample.CoolGuy("Nicolas");
nicolas.sing("November Rain"); // alerts "I'm singing November Rain"

【讨论】:

    【解决方案2】:

    那是完全不可能的; Javascript 不支持多重继承。

    特别是,您不能拥有从两个原型继承的单个对象。

    相反,您可以手动将两个原型中的所有功能复制到您的原型中。 (例如,使用 mixin 或 extends 方法)

    【讨论】:

    • OP真的不需要它来继承两个原型,可以使用mixins,不是吗?
    • @JuanMendes:是的;我想提一下。
    【解决方案3】:

    我不知道您对经典继承的依恋程度如何,但避免多重继承(以及菱形继承问题)的一种方法是使用 mixins(混入)。通俗地说:你在你的基类上添加更多的东西,直到它完成你想要的一切。

    【讨论】:

    • 例子来了?否则,应该是评论
    • 没有例子来,网上到处都是mixins的例子。我坚信这不应该是评论,因为它是一个答案。它回答了这个问题:如何避免钻石继承问题?
    • 多个mixin之间有冲突怎么办?您应该解释 mixins 如何避免这种情况,这是多重继承的主要问题
    • 这取决于你的 mixin 实现。你可以抛出一个错误,选择最后一个实现,保留第一个实现,进入一个 while(true) 循环并且永不退出,接管世界并奴役人类的生物质。 - Mixins 通过不需要构造函数来解决菱形继承问题,冲突解决超出了我的回答范围。我认为不需要完整的教科书回复,欢迎您提供自己的回复。
    • 感谢您的回复,我一直在研究如何扩展或混合我需要在这里实现的目标,并想出了多种方法来实现它。我想出的一个可以在这里找到:pastebin.com/An2UbzRA 非常感谢评论和意见
    【解决方案4】:

    感谢所有有效的答案,我会投票。我已经整理了一个更有用和更真实的示例,它似乎可以完成这项工作,所以我在这里提供了 an 答案,但看起来有很多方法可以做到这一点:

    function TXObject(settings) {
      this.transmit = function(data) {
        // Transmit data using settings
        console.log('Transmitting data: ' + data);
      }
    }
    
    function RXObject(settings) {
      this.receive = function(data) {
        // Receive data using settings
        console.log('Receiving data: ' + data);
      }
    }
    
    
    
    function Device(settings) {
      this.settings = settings;
    }
    
    Device.prototype.asTransmitter = function() {
      var txInstance = new TXObject(this.settings);
      this.transmit = txInstance.transmit.bind(txInstance);
      // Alternatively to wrap txInstance.transmit and add functionality..
      // this.transmit = function() { txInstance.transmit(...); }
      return this;
    }
    
    Device.prototype.asReceiver = function() {
      var rxInstance = new RXObject(this.settings);
      this.receive = rxInstance.receive.bind(rxInstance);
      // Same thing for receive..
      // this.receive = function() { rxInstance.receive(...); }
      return this;
    }
    
    Device.prototype.asTransceiver = function() {
      this.asTransmitter();
      this.asReceiver();
      return this;
    }
    
    var d = new Device({foo: 'bar'});
    console.log(d);
    var tx = new Device({foo: 'bar'}).asTransmitter();
    console.log(tx);
    var rx = new Device({foo: 'bar'}).asReceiver();
    console.log(rx);
    var txrx = new Device({foo: 'bar'}).asTransceiver();
    console.log(txrx);
    
    tx.transmit('hello');
    rx.receive('world');
    
    txrx.transmit('hello');
    txrx.receive('world');
    

    再次感谢!

    【讨论】:

      猜你喜欢
      • 2012-10-16
      • 2018-12-28
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-05
      • 2023-03-09
      相关资源
      最近更新 更多