Object Composition Vs Object Inheritance

Object Composition Vs Object Inheritance

Old forum URL: forums.lhotka.net/forums/t/66.aspx


RanceDowner1234 posted on Wednesday, May 10, 2006

Hey all:

I'm doing an OOP project for the first time.  And trying to learn CLSA.net at the same time.  So I'm trying to keep it as simple as possible to prevent brain shock.  But I'm also trying to do it right. 

I've been reading some article lately on Object Composition vs Object Inheritance.  Does anybody have any thoughts either way on the subject, especially using the CSLA 2.x framework.

Some articles I've read are:
http://brighton.ncsa.uiuc.edu/~prajlich/T/node14.html (seems to favor composition)
http://cpptips.hyperformix.com/cpptips/inh_vs_comp (seems to favor composition)
http://www.javapractices.com/Topic72.cjp (seems to favor compositon)

Of course none of these brilliant fellows give any real-life code examples on the differences between the two!

After a few hours of searching I finally found sort of an example for vb.net
http://discuss.develop.com/archives/wa.exe?A2=ind0502b&L=vbdotnet&T=0&F=&S=&P=1552

The above article focuses on "containing" a child object.  This seems like it would be hard to "bind" to the object using vb.net's datasource and bindingsource utilities.  Is there any other way to do Object Compositon?

Long story short... I would consider using Object Composition if I could find a good practical example or tutorial that explains how to implement it in the real world.  Does anybody know of any sites that show some good vb.net or c#.net examples of a class that uses Object Composition vs Inheritance?

Or if anyone is currently using Object Compositon with CSLA 2.x I would love it if you could post a couple of your classes and "base"classes (if "base" is what you call them in Composite terms).  Especially showing how and when you write to the database using these little module classes.

Thx

Rance Downer
rancedowner1234@hotmail.com




RanceDowner1234 replied on Thursday, May 11, 2006

I think I found my own answer, so I might as well post it incase any other lost soul is looking for an answer too.  They key came in finding out that Object "Composition" goes by another name...   Object "Delegation".  It also goes by another name "Object Aggregation".  In short... It's basically just the old VB6 way of doing OOP. 

I'm surprised many persons so strongly advocate it over inheritance.  But what do I know!  I'm a newbie to OOP.  Personally, though, I think this is one reason so many developers get turned off to OOP, is that sometimes OOP advocates get a little bit on the religiously ferverous side on ya!  That's a different subject, but for an interesing read on that topic you might read Rocky's Guest OP in the latest Visual Studio Magazine...  http://www.ftponline.com/vsm/2006_04/magazine/departments/guestop/

But back on topic...  I figured out how atleast how I think I would assemble an "Agregated" (I prefer that moniker) Object.  Some questions do arise though.

If I did use Agregation in CSLA.net I wondered primarily about ValidationRules:
* Where's the best place to put the ValidationRules... inside the module Objects or inside the Aggregate?  If I put them in the "Module" Objects how do I "stitch" them all together in the Agreggate to provide a common "broken rules" collection for users without resorting to all kinds of withevents and  event trapping on my base modules... which could lead to my objects not being serializable (or more difficult to make serializable)?  If I put them in the "Agreggate" Object do I have to keep copying and pasting similiar logic every time I implement one of the Modules.   And if I'm doing so much copying and pasting have I lost some value to the whole Object Oriented approach.

* Also I don't think there's really any good reason to inherit BusinessBase(Of Payment) and BusinessBase(Of LineItem) in the respective module objects.  But I did wonder?

Long story short... I think I'm going to decide on Inheritance chains over aggregation, being that my program isn't really that difficult, and my inheritance hierarchies will be rather small.  I don't think I'll be doing alot of overriding in my SubClasses.  Also my gut tells me that inheritance will work better with the CSLA.net framework than Agreggation.  For instance I think Business Rules will be easier to implement in an inheritance environment.  I don't want to do that many workarounds.  Thirdly I pretty much so just cringe at the idea of writing and implementing all those interfaces. 

But it will be fun to post how I think I would do aggregation.  If anyone has an actual better way of doing it though.... please.... post it by all means.  Or if anyone has any comments on my implementation that would help too.  Good or bad.

Note:  Some examples of aggregation I saw on the internet did not Implement the Interfaces in the aggregate object, they merely provided pointers to module objects.  But I chose to Implement the Interfaces because I will be databinding these objects to grids and controls in my winforms using datasources and the bindingSource control.  The only way I could figure out to accomplish this was to do a full blown delegation, which would emulate the base module properties.

Note2:  I didn't implement everything... it's just a sample... so I only did the DataPortal_Create and Fetch methods.  I haven't tried actually running this code it's just my thoughts on how I think I might do it.  I suppose it could get tricky when it came to the updating logic.  I found an article on Rocky's website that shows how to do updating using inheritance.  I imagine the same principles would apply in an Agreggate scenario.  So I used a similiar technique in the Fetch in this example.  In updating, I suppose I would just create an Update subroutine and pass in a command object, like he does in his article on inheritance.  Here's Rocky's advice... http://www.lhotka.net/Articles.aspx?id=e130b265-15cb-453d-9719-d5a944385fd3

The following example basically shows a ResidentialCustomerPayment which is an aggregate of Payment and LineItem.  For definition sake... a Line Item is in the context of an accountbook registry "line item".  I don't show it in the example but I will also want to use LineItem in deriving other objects like an ElectricBillStatement Object or a GasBillStatement Object.  I would also want to use the Payment class in agreggating other objects such as a CommercialCustomerPayment.

Anyway... without further musing... here's the code:

Imports Csla
Imports Csla.Data

Public Interface ILineItem
    Property LineItemID() As Integer
    Property EntryDate() As SmartDate
    Property EntryAmount() As Double
End Interface

Public Class LineItem
    Inherits BusinessBase(Of LineItem) 'Haven't implemented Business rule logic so I don't know if I really need to inherit from BusinessBase or not???

    Implements ILineItem

    Protected Overrides Function GetIdValue() As Object
        Return _LineItemID
    End Function

    Private _EntryAmount As Double
    Public Property EntryAmount() As Double Implements ILineItem.EntryAmount
        Get
            Return _EntryAmount
        End Get
        Set(ByVal value As Double)
            _EntryAmount = value
            PropertyHasChanged()
        End Set
    End Property

    Private _EntryDate As New SmartDate()
    Public Property EntryDate() As Csla.SmartDate Implements ILineItem.EntryDate
        Get
            Return _EntryDate
        End Get
        Set(ByVal value As Csla.SmartDate)
            _EntryDate = value
            PropertyHasChanged()
        End Set
    End Property

    Private _LineItemID As Integer
    Public Property LineItemID() As Integer Implements ILineItem.LineItemID
        Get
            Return _LineItemID
        End Get
        Set(ByVal value As Integer)
            _LineItemID = value
            PropertyHasChanged()
        End Set
    End Property

    Private Sub New()
        'Force Factory methods
    End Sub

    Public Shared Function NewInstance() As LineItem
        Return DataPortal.Create(Of LineItem)()
    End Function

    Public Sub Fetch(ByVal dr As SafeDataReader)
        With dr
            _LineItemID = .GetInt32("LineItemID")
            _EntryAmount = .GetDecimal("EntryAmount")
            _EntryDate = .GetSmartDate("EntryDate")
        End With
    End Sub
End Class

Public Interface IPayment
    Property CheckAmount() As Double
    Property CheckNumber() As String
    Property AppliesToPrincipal() As Double
    Property AppliesToInterest() As Double
End Interface

Public Class Payment
    Inherits BusinessBase(Of Payment) 'Haven't implemented Business rule logic so I don't know if I really need to inherit from BusinessBase or not???

    Implements IPayment

    Protected Overrides Function GetIdValue() As Object
        'Cant think of anything to return so I'm returning Nothing
        Return Nothing
    End Function

    Private _AppliesToInterest As Double
    Public Property AppliesToInterest() As Double Implements IPayment.AppliesToInterest
        Get
            Return _AppliesToInterest
        End Get
        Set(ByVal value As Double)
            _AppliesToInterest = value
            PropertyHasChanged()
        End Set
    End Property

    Private _AppliesToPrincipal As Double
    Public Property AppliesToPrincipal() As Double Implements IPayment.AppliesToPrincipal
        Get
            Return _AppliesToPrincipal
        End Get
        Set(ByVal value As Double)
            _AppliesToPrincipal = value
            PropertyHasChanged()
        End Set
    End Property

    Private _CheckAmount As String
    Public Property CheckAmount() As Double Implements IPayment.CheckAmount
        Get
            Return _CheckAmount
        End Get
        Set(ByVal value As Double)
            _CheckAmount = value
            PropertyHasChanged()
        End Set
    End Property

    Private _CheckNumber As Double
    Public Property CheckNumber() As String Implements IPayment.CheckNumber
        Get
            Return _CheckNumber
        End Get
        Set(ByVal value As String)
            _CheckNumber = value
            PropertyHasChanged()
        End Set
    End Property

    Private Sub New()
        'Force Factory methods
    End Sub

    Public Shared Function NewInstance() As Payment
        Return DataPortal.Create(Of Payment)()
    End Function

    Public Sub Fetch(ByVal dr As SafeDataReader)
        With dr
            _AppliesToInterest = .GetDecimal("AppliesToInterest")
            _AppliesToPrincipal = .GetDecimal("AppliesToPrincipal")
            _CheckAmount = .GetDecimal("CheckAmount")
            _CheckNumber = .GetString("CheckNumber")
        End With
    End Sub
End Class

Public Interface IResidentialCustomerPayment
    Property KilowattHoursUsed() As Double
    Property ResidentialRate() As Double
End Interface

Public Class ResidentialCustomerPayment
    Inherits BusinessBase(Of ResidentialCustomerPayment)
    Implements IResidentialCustomerPayment
    Implements ILineItem
    Implements IPayment

    Private mLineItem As LineItem
    Private mPayment As Payment

    Protected Overrides Function GetIdValue() As Object
        Return mLineItem.LineItemID
    End Function

    Private Sub New()
        'Forces Factory Methods
    End Sub

    Public Shared Function NewInstance() As ResidentialCustomerPayment
        Return DataPortal.Create(Of ResidentialCustomerPayment)()
    End Function

    Public Shared Function GetInstance(ByVal id As Integer) As ResidentialCustomerPayment
        Return DataPortal.Fetch(Of ResidentialCustomerPayment)(id)
    End Function

    Protected Overrides Sub DataPortal_Create(ByVal criteria As Object)
        mLineItem = LineItem.NewInstance()
        mPayment = Payment.NewInstance()
    End Sub

    Public Sub Fetch(ByVal dr As SafeDataReader)
        With dr
            _ResidentialRate = .GetDecimal("ResidentialRate")
            _KilowattHoursUsed = .GetDecimal("KilowattHoursUsed")
        End With

        'Note:  I suppose I could have just called the properties directly
        'But I chose to have an easy function called Fetch to be able to
        'pass a SafeDateReader
        Call mLineItem.Fetch(dr)
        Call mPayment.Fetch(dr)
        MarkOld() 'For Good measure
    End Sub

    Protected Overrides Sub DataPortal_Fetch(ByVal criteria As Object)
        MyBase.DataPortal_Fetch(criteria)

        Dim dr As SafeDataReader
        'Put logic here to call from Database and populate dr
        Call Fetch(dr)
    End Sub

#Region " IResidentialCustomerPayment"

    Private _KilowattHoursUsed As Double
    Public Property KilowattHoursUsed() As Double Implements IResidentialCustomerPayment.KilowattHoursUsed
        Get
            Return _KilowattHoursUsed
        End Get
        Set(ByVal value As Double)
            _KilowattHoursUsed = value
            PropertyHasChanged()
        End Set
    End Property

    Private _ResidentialRate As Double
    Public Property ResidentialRate() As Double Implements IResidentialCustomerPayment.ResidentialRate
        Get
            Return _ResidentialRate
        End Get
        Set(ByVal value As Double)
            _ResidentialRate = value
            PropertyHasChanged()
        End Set
    End Property

#End Region

#Region " ILineItem "
    Public Property EntryAmount() As Double Implements ILineItem.EntryAmount
        Get
            Return mLineItem.EntryAmount
        End Get
        Set(ByVal value As Double)
            mLineItem.EntryAmount = value
            PropertyHasChanged() 'treat delegated propertyChange same as local propertyChange
        End Set
    End Property

    Public Property EntryDate() As Csla.SmartDate Implements ILineItem.EntryDate
        Get
            Return mLineItem.EntryDate
        End Get
        Set(ByVal value As Csla.SmartDate)
            mLineItem.EntryDate = value
            PropertyHasChanged() 'treat delegated propertyChange same as local propertyChange
        End Set
    End Property

    Public Property LineItemID() As Integer Implements ILineItem.LineItemID
        Get
            Return mLineItem.LineItemID
        End Get
        Set(ByVal value As Integer)
            mLineItem.LineItemID = value
            PropertyHasChanged() 'treat delegated propertyChange same as local propertyChange
        End Set
    End Property

#End Region

#Region " IPayment "

    Public Property AppliesToInterest() As Double Implements IPayment.AppliesToInterest
        Get
            Return mPayment.AppliesToInterest
        End Get
        Set(ByVal value As Double)
            mPayment.AppliesToInterest = value
            PropertyHasChanged() 'treat delegated propertyChange same as local propertyChange
        End Set
    End Property

    Public Property AppliesToPrincipal() As Double Implements IPayment.AppliesToPrincipal
        Get
            Return mPayment.AppliesToPrincipal
        End Get
        Set(ByVal value As Double)
            mPayment.AppliesToPrincipal = value
            PropertyHasChanged() 'treat delegated propertyChange same as local propertyChange
        End Set
    End Property

    Public Property CheckAmount() As Double Implements IPayment.CheckAmount
        Get
            Return mPayment.CheckAmount
        End Get
        Set(ByVal value As Double)
            mPayment.CheckAmount = value
            PropertyHasChanged() 'treat delegated propertyChange same as local propertyChange
        End Set
    End Property

    Public Property CheckNumber() As String Implements IPayment.CheckNumber
        Get
            Return mPayment.CheckNumber
        End Get
        Set(ByVal value As String)
            mPayment.CheckNumber = value
            PropertyHasChanged() 'treat delegated propertyChange same as local propertyChange
        End Set
    End Property

#End Region

End Class









malloc1024 replied on Monday, May 15, 2006

One of the fundamental principles of OOP is favor composition over inheritance.  Composition will give you more maintainable and flexible code.  Inheritance is overused and abused way too often.  BTW, the articles you listed did give code examples.  They said to look at design patterns.  Design patterns will show the power that composition has over inheritance.  I would strongly suggest that you get a good OOP/Design Patterns book.  It will help you much more than Rocky's book in the long run.  Knowing the fundamentals will give you more appreciation on what Rocky did and also help you become a much better programmer.

MichaelBosch replied on Tuesday, May 16, 2006

Malloc: 
I like you're test replacing "is-a" with "behaves as a".  Any suggestions on the best OOP/Design Patterns book?  I bought the Head First design patterns book, but it seems like a very basic, simplistic presentation of design patterns.  Maybe thats a good thing?  Any other suggestions...?

malloc1024 replied on Tuesday, May 16, 2006

I read the "Head First" book and enjoyed it.  I would strongly recommend this book to anyone who wants to learn about design patterns and OOP.  The examples are simplistic, but this aids the user in trying to understand the pattern.  If you are already very familiar with OOP and design pattern you won't get much out of the book.  However, this is true with most design pattern books.  If you want something more difficult, you could always try the original GoF Book.  The book is notorious for its difficulty though.   I would also recommend Fowler’s “Patterns of Enterprise Application Architecture” and Kerievsky’s “Refactoring to Patterns” and “Design Patterns Explained”.  These are the better books that I have read.  Rocky recommends David West’s “Object Thinking”.  I have not read it so I can not comment on it.  Maybe someone in this forum can.  If I can remember any more, I will list them.   Finding good books can be difficult and expensive.  If anyone has anymore recommendations, please share them.   

Head First Design Patterns:
http://www.amazon.com/gp/product/0596007124/103-6049992-6751013?v=glance&n=283155

Refactoring to Patterns:
http://www.amazon.com/gp/product/0321213351/103-6049992-6751013

Patterns of Enterprise Application Architecture:
http://www.amazon.com/gp/product/0321127420/103-6049992-6751013?v=glance&n=283155

 Design Patterns Explained:
http://www.amazon.com/gp/product/0201715945/103-6049992-6751013?v=glance&n=283155

 Object Thinking:
http://www.amazon.co.uk/exec/obidos/ASIN/0735619654/202-8705868-5724646

Bayu replied on Wednesday, May 17, 2006

Hey,

Don't forget to mention the classic:

Design Patterns: Elements of Reusable OO Software, by the 'Gang of Four'.
http://www.amazon.com/gp/product/0201633612/sr=8-1/qid=1147851537/ref=pd_bbs_1/002-5875380-8679251?%5Fencoding=UTF8

Actually, this book is all I ever read 'on paper' about design patterns. It is more like a catalog then a tutorial. Really great reference to have on your workbench to look up the 20+ most commonly used design patterns of all. With sample code (not dotnet, but very comprehensible), UML.diagrams and detailed explanation of the pros and cons of each pattern. IMO: a must-have!

(Sometimes, when discussing these matters, I tend to get a little carried away Wink [;)]).

Check it out!
Bayu


malloc1024 replied on Wednesday, May 17, 2006

I mentioned the GoF book.  I just forgot to provide the link to it.  Thanks for posting the link.

DancesWithBamboo replied on Sunday, May 14, 2006

Hi Rance-


I see you answered your own post but I thought I would add a couple of thoughts.  My first consideration when deciding to use inheritance is wheter the realtionship I am modeling is a "is-a" or a "has-a" relationship.  The is-a is more likeley to be modeled as an inheritance structure like "address is a contact"".  The has-a is modeled as a composition such as "a customer has an order".

After that, inheritance is almost always more complicated to design correctly in the real-world environment.  It seems that all of the requirements for a project are never known at design time and it is much easier to add functionality by composition than inheritance later on in the product's lifecycle. 

In your answer you only use interface inheritance so I don't think what you did can really be compared to composition since you didn't inherit functionality.  Interface inheritance allows you to act on all the objects in the same way (polymorphism) but doesn't give you any any less work to do in the derived class since you have to implement the methods anyway.  Not to say that it is right or wrong, but I haven't seen anyone do what you did.  Basically you said that a ResidentialCustomerPayment is-a LineItem and has-a LineItem.  I don't see why you would do this?  I would probably make a full LineItem class and give it to the customer as a property; then access it as ResidentialCustomerPayment.Charge.EntryAmount.  But, it is always hard to give answers without knowing all of the requirements!  It just doesn't seem right for it to be in both types of relationships at the same time.

Another advantage to composition in CSLA is the use of switchable objects.  With LineItem as its own full featured object, it could be a child when needed and a parent when needed.  This allows you to pluck an object out of its hierarchy and use it on an add/edit form without the need for the whole tree.

There are always many ways to design objects and it is always fun to discuss the options.


xal replied on Monday, May 15, 2006

DancesWithBamboo:

Grady Booch?

Andrés

malloc1024 replied on Monday, May 15, 2006

Bamboo,

The "is-a"  test is misleading.  Replace the "is-a" test with a "behaves as a" test.  Inheritace should be based on behavoir not data.  The "behaves as a" test will help enforce this.

RanceDowner1234 replied on Thursday, May 18, 2006

Thanks everybody (especially Dances With Bamboo) for taking a look and offering some thoughts.  Thanks especially for the links to the books I will check them out. This was definitely my first attempt at composition (aggregation), so I needed some input.

In my secenario a ResidentialCustomerPayment "is a" (or "behaves as a") Payment which in turn "is a" LineItem.  Infact the "Primary Key" in the database for a ResidentialCustomerPayment will be "LineItemID".  The primary key for any other derived objects such as BusinessCustomerPayment would also be "LineItemID".  So, first of all, am I correct in concluding that inheritance might be the way to go here?

But for theory's sake... if I was to go the Composition (aka Aggregation) route...

I agree with Dances With Bamboo that the interface implementation route in my code sample didn't seem like any less work than just copying and pasting the properties into each "aggregate" object.  As I was coding the example it did seem like it would be just easier to create a full fledged LineItem Object and then pass it as a property. 

I suppose the "pass the reference" model would look something like...

Public Class LineItem
   
Inherits BusinessBase(Of LineItem)
   
    'Add properties such as: LineItemID, EntryDate, EntryAmount

    'Add some factory instantion: NewInstance( )
End Class

Public Class Payment
    Inherits BusinessBase(Of Payment)

    'Add properties such as: CheckNumber, CheckAmount, AppliesToPrincipal, AppliesToInterest

    'Add some factory instantion: NewInstance( )
End Class

Public Class ResidentialCustomerPayment
   
Inherits BusinessBase(Of ResidentialCustomerPayment)

    Public Shared Function NewInstance() As ResidentialCustomerPayment
        Return DataPortal.Create(Of ResidentialCustomerPayment)()
    End Function

    Protected Overrides Sub DataPortal_Create(ByVal criteria As Object)
        _LineItem = LineItem.NewInstance( ) 'Instantiate a private LineItem Object
        _Payment = Payment.NewInstance( ) 'Instantiate a Private Payment Object
    End Sub

    Private _LineItem As LineItem
    Public ReadOnly Property LineItem( ) As LineItem
        Get
            Return _LineItem
        End Get
    End Property

    Private _Payment As Payment
    Public ReadOnly Property Payment( ) As Payment
        Get
            Return _LineItem
        End Get
    End Property

End Class

Then in GUI code if I wanted to refer to the "derived" properties in ResidentialCustomerPayment I could just say something like

Dim rcp as ResidentialCustomerPayment = ResidentialCustomerPayment.GetInstance( )

MsgBox rcp.LineItem.EntryAmount.ToString.Trim
MsgBox rcp.LineItem.EntryDate.ToString.Trim
MsgBox rcp.Payment.CheckNumber.Trim
MsgBox rcp.Payment.AppliesToPrincipal.ToString.Trim

etc. etc.

But the reason in specific I was going that interface route was because I wanted to take advantage of visual studio.net windows data-binding... especially on a datagridview control.  To explain...

In Visual Studio I have been creating a "Data Source" out of my objects.  Then on the forms I create a BindingSource Control and set it's datasource property to My object.  In this case I would set the datasource to the ResidentialCustomerPayment object.

Then I would set the datagridview control datasource to the BindingSource control.  But when you goto add fields to the datagridview you are only able to add "base" properties.  You don't get the option of seeing properties in child (aggregated) objects.   And in my case I want to be able to show LineItemID, EntryDate, EntryAmount,  CheckNumber, CheckAmount, AppliesToInterest on the same datagridview control.

To work around this I figured I could just implement the interfaces on the child objects and then delegate the "base" properties to the child properties.

Also when I'm dealing with other control types, and databinding....  If I use the "passing the reference" model above it's not quite as difficult, but it's a little messy.  In order to use Microsoft's BindingSource controls I have to create separate BindingSource controls for both my Payment and LineItem Objects using the respective DataMember properties on each control.  Then I can add databindings to say textbox, maskedTextbox, DateTimePicker and other controls.  It works... but I was hoping for a simpler, cleaner solution.

Should I just forget about Microsoft's BindingSource controls and just populate any grids or controls the old-fashioned unbound way?

I kind of like the new BindingSource controls.  They're pretty cool.  I've always avoided DataBinding in the past because Visual Studios previous implementations of it kind of stunk up the joint.  So if anyone can think of another way to use it... along with aggregation... your thoughts would be appreciated.

Rance








malloc1024 replied on Thursday, May 18, 2006

A payment does not behave as a lineitem. Therefore inheritance is not appropriate in this situation.  Shouldn’t there be an invoice or order object that contains multiple lineitems?  Are payments actually applied to a lineitem or are they applied to an account?  Your classes should not be designed with binding in mind.  You will not get a very good design this way.  If you want to bind multiple objects you could try a façade that wraps multiple objects to provide a simpler interface.

RanceDowner1234 replied on Thursday, May 18, 2006

Thanks for your input malloc1024.  In this case the definition of a "LineItem" is an entry in an Accountbook, not an InvoiceItem.  A LineItem can be either a debit or a credit.... similiar to a checkbook "line item".   In my application there is a AccountBookQuarter Parent Object.  Then there are Invoice "LineItems", Payment LineItems, Interest LineItems.  So to answer your question directly, yes Line Items are applied to an Account, not an Invoice.

There are different types of Invoice LineItems.  In this case my company sells wholesale energies to smaller Telephone, Gas, and Electric companies.  But a Telephone company receives a different kind of Bill, with different fields on it, than a Gas or Electric Company Does.

Also there are different kinds of Payment methods.  For instance a ResidentialOnlyServiceProvider is only allowed to pay by Check or Money Order.  A CommercialServiceProvider is allowed to pay by check or Automatic Fund Transfer.  There's some other logic too.  For instance Telephone "ResidentialOnly" service providers are able to correct their own bill, namely "kilowatt hours used", sending that corrected information in with the payment.  A Telephone CommercialServiceProvider cannot correct their bill, but must call in first, we correct the invoice, and then re-bill them.  So on a Telephone ResidentialServiceProvider's payment we want to track what they stated on their returned bill, and before voiding out and correcting the invoice line item itself. 

I'm sure all that was clear as mud.  It's kind of muddy business rules :0)

Anyway... I tried setting up the inheritance chain as follows:

LineItemBase:  With EntryID, EntryDate, EntryAmount (Debit or Credit)

InvoiceBase (Derives from "LineItemBase"): With Fields that all Invoices hold in common.  Note: This object does indeed have a collection of InvoiceItems that applies to the total billable amount
TelephoneCompanyInvoice (Derives from InvoiceBase): With fields particular to an Telephone company invoice
GasCompanyInvoice: With fields particular to an Gas company invoice
ElectricCompanyInvoice: With fields particular to an Electric company invoice

PaymentBase (Derives from "LineItemBase"): With fields that all Payments have in common (for instance Check Number, and check amount, what part of payment applies to Principal, and what part applies to interest)
TelephonePayment (Derives from PaymentBase):  Corrected Kilowatt hours is an extra field
TelephoneCommercialPayment (Derives from PaymentBase):  But adds the Automatic Fund Transfer routing number
GasPayment (Derives from PaymentBase):  Nothing extra right now, but perhaps in future???
ElecPayment (Derives from PaymentBase):  Nothing extra right now, but perhaps in future???

Anyway... long story short...  I kinda thought PaymentBase looked like a "behaves as a" scenario.... but even if it is... what's your take... inheritance or aggregation?

Thx again.  I'm trying to get this OOP down.  But boy, what a deep subject.  Most people say your first OOP project fails.  I'm trying not to fall into that category.  I think Lhotka's set me in the right direction with his framework.  I'm starting to grasp concepts like singleton instantiation, and factories.  But like I said, I suppose it could be real easy to shoot yourself in the foot on this aggregation vs inheritance thing.  Especially if some of the business rules change down the road.

Also thanks for the idea on the facade.  I imagine that could take care of my databinding issues if I went with aggregation.

Rance

Copyright (c) Marimer LLC