When to use “is a” or “has a”? [closed]
https://softwareengineering.stackexchange.com/questions/307162
-
11-12-2020 - |
题
In my node.js application, I have a queue class which has push
and pop
methods and a data
property. I have an Event
class which handles an event and pushes it on to the queue.
If I think object oriented, is the relationship between queue and event better modeled as "is a" (inheritance) or "has a" (composition)?
First approach:
var util = require('util'),
array = [];
function Q(source){
this.data = source;
}
Q.prototype.push = function(x){
this.data.push(x);
};
Q.prototype.show = function(){
console.log(this.data);
};
function Event(y){
Q.call(this, y);
}
util.inherits(Event,Q);
Event.prototype.trigger = function(bb){
//some logic
this.push(bb);
};
var x = new Event(array);
x.trigger('hi');
x.show();
Second approach :
var array = [];
function Q(source){
this.data = source;
}
Q.prototype.push = function(x){
this.data.push(x);
};
Q.prototype.show = function(){
console.log(this.data);
};
function Event(y){
this.arr = new Q(y);
}
Event.prototype.trigger = function(bb){
//some logic
this.arr.push(bb);
};
var x = new Event(array);
x.trigger('hi');
x.show();
解决方案
Conceptually, inheritance (is-a) is a specialization of composition (has-a). (from Reg Braithwaite) Both accomplish the same thing (which is why you can ask a question like this), but inheritance lacks the flexibility of composition. Inheritance makes your code rigid.
From a practical view, this doesn't matter as much in JavaScript since JavaScript isn't limited to single inheritance. What we're calling inheritance is actually some prototype patching and function delegation. There's nothing stopping us from creating a mixin from several "types". This has more in common with Go's type composition than Java or C#'s inheritance model. It doesn't make your code as rigid.
Still, it does seem strange to say an Event
is-a Queue
. Is it really? It seems more likely that an Event
is a model of some action in your app and it uses (has-a) a Queue
to manage its workflow. If an Event
is truly a Queue
, I should be able to use it anywhere I use a Queue
without a second thought:
var q = new Event();
q.push("hi");
q.pop();
This doesn't seem right to me. It's a stretch. This is a perfect place to avoid inheritance in favor of composition.
See also: Liskov substitution principle