Javascript Diamond Inheritance Structure

Using node, but finding a way to inherit diamonds in 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(); 

There is no problem ... but then I need to do everything that is available in Foo and Bar (and Base), in another all-encompassing object:

 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' is printed twice, which is not what I was after. Performing such an inheritance is probably not the best way to find alternatives / suggestions for working with this diamond shape structure.

PS They didn’t include the source code, but changed, I hope, to simplify it - I did it manually, I don’t think there are errors, but the point that I am trying to find should be there.

+4
source share
4 answers

Can you use delegation?

 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(); } 

You can also use mixins, but you need to add it to your class system. Ext-JS supports 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" 
+1
source

It is absolutely impossible; Javascript does not support multiple inheritance.

In particular, you cannot have one object that inherits from two prototypes.

Instead, you can manually copy all the functions from both prototypes into a prototype. (e.g. using mixin or extends method)

+1
source

I don’t know how you are attached to classical inheritance, but one way to avoid multiple inheritance (and the problem of diamond inheritance) is to use mixins (mix in). Unprofessional: you put more material into your base class until it does everything you need.

+1
source

Thanks for the answers that are valid and I will vote. I put together a more useful and real-world example that seems to do the job, so I provided an answer here, but there seem to be several ways to do this:

 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'); 

Thanks again!

0
source

Source: https://habr.com/ru/post/1480534/


All Articles