Jump to content

Inheritance versus Composition


Recommended Posts

Nobody moved the relevent posts across, so I'll have to cut and paste bits here instead instead of quote the originals.
 
 
Hmm. Composition Vs Inheritance. I'm half tempted to show you an example without classes at all just to show that using lists has nothing to do with inheritance. As for composition. I though you were proffering the Composite Pattern. When you talk of composition, I think of [object] composition like the image below which is a form of inheritance IMO :wacko:
 
post-15232-0-06627700-1432178606_thumb.p
 
We are already foundering on terminology so it is no wonder people have a tough time with OOP. :P
 

I don't want to weigh this relatively focussed topic down with previous discussions which may or may not be applicable and to which I was not a party.  I also don't mean to be nasty but your usage of both has no relevance to the discussion.

Nothing to do with discussion. It is the name of a criticism of OOP that what methods and properties that an object should consist of, is subjective and based on the viewpoint of the programmer. If you haven't had or seen that argument; I would be very surprised.The relevance is implicit. The Composite pattern yields a "Bottom up design". The Lists are a "Top Down design" these are supersets to design patterns in any paradigm. You are looking at the system and saying "what pattern can I apply"?. I am looking at just the test management and whats the best way to solve this bit. (oh how I wish we could inherit from  TreeView)
 

The obvious drawback of your idea is the static linkage to the List class.  While the List class is most likely a lovely piece of work, if you want to implement a Frame as a different kind of grouping (don't ask me, I'm just theorizing, perhaps a conditional looping of individual elements until a condition is met) then either you build that into your List class or you implement it separately in your child class.  By moving the List functionality into the child class, each child is free to implement whatever method of aggregation they see fit without requiring interface bloat.  Each item implements whatever it needs.  You could have several different flavours of collections (lists) which do things different based on some corner cases.

So this is a "what if" scenario that doesn't really pose an issue for lists, but is the type of thing the pattern was designed for. I'm not even sure I understand "interface bloat" in terms of a LabVIEW implementation since I either use the TList Vis or use the "Frame" VIs which at this pint probably only has one or two VIs (Get Result and Execute?). Each child is also free to handle its own "aggregation" however it sees fit. You can also have "several different flavours of collections (lists)" as well as Steps, Actions and any other classes you care to include but the main thing we want to do is move them around within the list, change their order and add and remove them so it;s hardly bloat if we are actually using those functions.
 

So imagine a "collection" which internally manages a List (your class). When dealing with a collection (strictly typed child of Frame), you have the exposed methods for the list, when working with Frames (when you don't need to know whether it's a list or not) you have a much cleaner interface. By moving your same List class up two levels of the hierarchy you gain a lot of flexibility and remove static linkage to the functionality of your list. What are the downsides you see with this approach? The only downside I see is the creation of some proxy VIs which, depending on your taste might be enough to sway you


I consider a collection to be the same as a list, so your first sentence doesn't make a lot of sense. But no. In LabVIEW you don't have the exposed methods unless you override explicitly so I'm not going to create a VI in the child for every VI in the base jsut to give me the right coloured squares. I will just use the base class VIs. Granted in C#, Delphi et.al your code completion list will be shorter so you can reduce "interface bloat", but they get those automatically without writing skeleton functions. We don't have that in LabVIEW so interface bloat is moot as far as I'm concerned.

 

The downsides I see is that it really doesn't give you much and it kind of fixes you into an application architecture that may not be that good for other aspects. For Sequences and Steps (slipped back into TS terminology as we don;t really know what a Frame is) they are just line items in a list. It is "actions" that actually do stuff and everything else is just ordering the actions. All you really need is a list and execute to manage sequences, steps and actions. What you actually execute is a different matter.

Edited by ShaunR
Link to comment
Nobody moved the relevent posts across, so I'll have to cut and paste bits here instead instead of quote the originals.

 

Hmm. Composition Vs Inheritance. I'm half tempted to show you an example without classes at all just to show that using lists has nothing to do with inheritance. As for composition. I though you were proffering the Composite Pattern. When you talk of composition, I think of [object] composition like the image below which is a form of inheritance IMO :wacko:

 

 

I am and I am.  I am referring to both the composite pattern AND composition, both terms being used correctly.  The idea of a Frame containing a List class internally and handling this WITHIN the borders of it's encapsulation : not exposed) is composition in the classical sense, one class containing another in order to implement some aspect of the functionality in a sub-class.  The fact that this Frame incorporating a List (which accepts Frames as items) is also a Frame object is the Composite Pattern.  The item representing multiple instances of a defined object type is transparently exchangeable with an item representing a single instance of the same object type.

 

As to your image.  Hmm, I see no evidence of composition here at all.  There's only a single object wire, no observable sub-objects.  I think you're simply showing inheritance at work here which is most definitely NOT composition (in the generally accepted sense).  If you're defining some super-literal definition of composition then you need to make that clear but the standard definition of composition is that a class "car" can have  four "wheels".  If each "wheel" is itself an object (different inheritance hierarchy than "car") then by giving an object "car" four member classes of type "wheel" allows the actual implementation of "wheel" to vary independently of "car" and also allows run-time substitution, something which Inheritance cannot.  It would theoretically be possible to replace four standard "wheels" with jet propulsion units without having to modify "car" at all.  Only the Interface for "wheel" needs to be compatibly with the implemented functionality.

 

In your case, "Truck" IS A "Vehicle".  This is Inheritance.  In my example "car" HAS "wheel"s, this is composition.  It's identity versus possession.  Two very different approaches to essentially different problems.

 

Nothing to do with discussion

 

 

Good, then let's move on.

 

So this is a "what if" scenario that doesn't really pose an issue for lists, but is the type of thing the pattern was designed for. I'm not even sure I understand "interface bloat" in terms of a LabVIEW implementation since I either use the TList Vis or use the "Frame" VIs which at this pint probably only has one or two VIs (Get Result and Execute?). Each child is also free to handle its own "aggregation" however it sees fit. You can also have "several different flavours of collections (lists)" as well as Steps, Actions and any other classes you care to include but the main thing we want to do is move them around within the list, change their order and add and remove them so it;s hardly bloat if we are actually using those functions.

 

 

Well I think a "What if" scenario when the problem has been defined as variable, i.e. not knowing which requirements are going to come next as was expressed in the original post, is an important thing to consider.

 

The aspect of Interface bloat is easy to understand.  If I take one of your Frame objects I can call each and every public method of your List class on my Frame.  Even if they're not required.  Even if they're not on the Menu but they are there and any tool which auto-populates a menu to show accessible functions will be bloated.  The methods are there and supported.  I'm referring to the actual Class interface, not whatever is shown to (or hidden from) the user.

 

Another topic: So which object type does your List contain?  Some generic datatype?  So I could feasibly call Frame.Add Item and pass it an Action and similarly call Action.Add Item and pass it a Frame?  Or do you have some way of hiding these methods of your List after inheritance?  The only thing I can think of is "Community" scope but IIRC this is bugged to hell.

 

I consider a collection to be the same as a list, so your first sentence doesn't make a lot of sense. But no. In LabVIEW you don't have the exposed methods unless you override explicitly so I'm not going to create a VI in the child for every VI in the base jsut to give me the right coloured squares. I will just use the base class VIs. Granted in C#, Delphi et.al your code completion list will be shorter so you can reduce "interface bloat", but they get those automatically without writing skeleton functions. We don't have that in LabVIEW so interface bloat is moot as far as I'm concerned.

 

 

The bolded term is simply wrong.  Flat out, no discussion.  I can call ANY public methods you have defined for your List on any Frame object.  It will call the Parent implementation (I think this is what you're getting at) but I can do this, it's legal and there's nothing to stop me doing it.  Depending on how you present your VIs to the end-user you may have any subset of the interface listed there, but doing so does NOT remove them from the interface.  The methods are there, they can be called and they do something.  You even say later that "I will just use the base class VIs.".  Exactly.  But why have those methods available when they're not always needed?  That's interface bloat right there.  Parent methods are just as much a part of an object's interface as it's own.  This is because the child IS A parent (inheritance).  Making a shorter list, looking only at that level of the inheritance hierarchy or just plain pretending the methods do not exist for that object does not mean that the methods are not there.

 

So for Frames which are only a single item and will only ever BE a single item, the List methods are bloat.  Taking things further, if (beyond Frame initialisation) you never need to deal directly with the List functionality, having them there is bloat, exposed methods which at best confuse and at worst destroy any encapsulated functionality you might have implemented.  What if I choose to Add a new item to a List half way through execution so that the currently executed step is suddenly a different one?  Why have methods available which are unneccessary?

 

 

The downsides I see is that it really doesn't give you much and it kind of fixes you into an application architecture that may not be that good for other aspects. For Sequences and Steps (slipped back into TS terminology as we don;t really know what a Frame is) they are just line items in a list. It is "actions" that actually do stuff and everything else is just ordering the actions. All you really need is a list and execute to manage sequences, steps and actions. What you actually execute is a different matter.

 

Here we have things backwards.

 

Inheritance (inheriting from List) fixes us into the fact that each and every Frame is a List for ever and ever, immutable.

 

Using Composition, those Frames which need to be a List can manage their list privately, knowing what to do when told to execute.  If one wants to have a Collection, one wants to have a State machine, one wants to have a Client-Server connection, if one wants to pick random items from disk or whatever then each and every Frame is free to implement the grouping methodology it requires and handle it appropriately when told to execute.  That fixes you into nothing.  It frees you to do whatever you need whenever you need.  You can access the EXACT same functionality as with Inheritance but the List methods will NOT be callable on Frame.  When a Frame with an internal List is told to execute, it will call the appropriate methods on it's List without the caller needing to know or see any of it.  THIS is the composite pattern combined with composition.  Allowing you to treat a List of Frames as a Frame as the same type of object is the composite pattern.  Using an internal List to give extra functionality and choosing which methods (if any) are exposed is composition.  By doing so you also expose "Add" functions which accept ONLY Frames which prevents a cross-communication with other object types, something which the normal "List" methods cannot do.

 

Shane

Link to comment
  • 2 months later...

By the way, I recently came across several discussions on the best way to implement the "Composite pattern".

 

  1. Some claim that the interface for adding, removing and listing sub-objects (Interface, not the actual code - this still leaves the concrete implementation the freedom to implement whichever method of grouping they require) should be part of the base object type.
    This still feels like interface bloat to me.  I am forcing a single object (say, a Circle) to implement methods like "Add Child" or "Remove Child" even though those methods make no sense for that object.  You can't add anything to a Circle without violating it's identity as a circle.
  2. Others claim that two differing interfaces are required, one with and one without the extra methods.
    The addition of a "Is composite?" option allows the user to then determine whether the object is comprised of sub-objects or not (or whether it's even capable, even if it currently is not).  A static cast could then be made to allow access to the extra methods if really required.

I tend to think sometimes, within certain application spaces, that a sequence of test routines (for example) are not simply a collection but the ordering is important and more often than not, leaving out a single step will negate the benefit of the entire sequence.  Can this be aligned with the composite pattern? Is there a different name for this?  It's like using the composite pattern during object creation but not beyond that.  A Sequence can be created using single steps or other sequences which in turn can comprise of single steps or other sequences which in turn......  This seems to obey the ideas of the somposite pattern but the ability to access/modify or delete sub-objects afterwards can be quite detrimental in these situations.

 

Has anyone else got an opinion on this?

Edited by shoneill
Link to comment

On a slightly different note:

 

In the original discussion leading up to this side thread the ball was brought to roll by the mention of "If you derive Sequence and Step from a List object.".  This involves inheritance, with the derived class referring to the class which has inherited from some base class.

 

But later (in this thread) it has just occurred to me that the following text "show you an example without classes at all just to show that using lists has nothing to do with inheritance" seems to contradict that.

 

Perhaps we have our lines crossed?  Perhaps you meant to refer to object composition in your original "derive" comment?  In this case we're actually talking about the same thing.  The entirety of the "Inheritance vs Composition" bases around the typical interpretation of the term "derived class" which is pretty well established to involve inheritance.  If it was not meant in that sense, then the entire discussion is moot.  this would also explain your surprise at the discussion even being about composition vs inheritance at all.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.