tags:

views:

135

answers:

2

I'm trying to wrap my head about how to properly implement an OOP design for business objects that:

  1. Have a "master list" in a database (ex. classifications)
  2. Are a part of another object as a property (i.e. object composition) but with additional properties

Here is where I'm stuck on the theory. Suppose that I have a Classification object, inheriting from the abstract class BusinessObject with the CRUD functions defined (MustOverride). This will give me:

Public MustInherit Class BusinessObject
    Public Sub New()

    End Sub

    Public MustOverride Function Create() As Boolean
    Public MustOverride Sub Read(ByVal id As Integer)
    Public MustOverride Function Update() As Boolean
    Public MustOverride Function Delete() As Boolean
End Class

Public Class Classification
    Inherits BusinessObject

    <Fields, properties, etc. for ID, Name (or Description), and 
     IsActive. DB table has only these 3 fields.>

    Public Sub New()
        MyBase.New()
    End Sub

    Public Overrides Function Create() As Boolean
        Dal.Classifications.Create(Me)
    End Function

    Public Overrides Function Delete() As Boolean
        Dal.Classifications.Delete(Me)
    End Function

    Public Overloads Overrides Sub Read(ByVal id As Integer)
        Dal.Classifications.Read(Me)
    End Sub

    Public Overrides Function Update() As Boolean
        Dal.Classifications.Update(Me)
    End Function
End Class

This will allow me to use the Classification object on a form where a system admin can manage the master list of Classifications in the system. No issue here.

Now, I want a Customer object to have a property of type Classification (object composition) but with one caveat - the Classification object requires an additional field, Level, when it becomes a property of the Customer object. Level is a logical part of Classification according to the business - a Classification has an application-user-entered numeric level. So I created a class CustomerClassification inheriting from Classification:

Public Class CustomerClassification
    Inherits Classification

    Private _level As Integer

    Public Property Level() As Integer
        Get
            Return _level
        End Get
        Set(ByVal value As Integer)
            _level = value
        End Set
    End Property

    Public Sub New()
        MyBase.New()
    End Sub
End Class

And the Customer object will be composed of CustomerClassification:

Public Class Customer
    Inherits BusinessObject

    Public Property Classification() As CustomerClassification
    ........ etc
End Class

Now, my design problem is that the Create, Read, Update and Delete functions are still exposed in the CustomerClassification object:

Dim c as New Customer
c.CustomerClassification.Update() ' <-- Not desirable!

What kind of other design could I implement here? It's obvous that I'm designing this the wrong way, but I don't see an easy alternative pattern. I don't want to repeat the code in the CustomerClassification class by not inheriting Classification and repeating all the field and property code, but I also don't want to expost CRUD functions to the CustomerClassification level. What am I missing in looking at the overall class design?

EDIT: Saving the classification level to the database will be handled by the customer object, because the database is legacy and the field for Level is defined in the customer table.

A: 

So, if I understand correctly you want the Update() function available only to the Customer class.

If your Classification and Customer classes are deployed in the same assembly, you can mark the Update() function as friend. This will make it inaccessible to classes outside that assembly.

Dave Swersky
I want both the Classification class and the Customer class to have the CRUD functions, but I don't want CustomerClassification to have them. Should I instead just have two properties for the classification in the Customer class: ClassificationID and Level, foregoing composition?
HardCode
The idea was to have a ComboBox on the customer form containing a List(of Classification), and setting Customer.CustomerClassification = ComboBox.SelectedItem.
HardCode
+1  A: 

If I understand your problem correctly, your Customer class does not need to aggregate an instance of the actual Classification class. It needs to have an instance of a separate class, which specifies the level and the type of Classification, represented by an ID or enum value. The Classification class should be used only in the scenario of an admin maintaining the list of classification IDs/enum.

Franci Penov
Okay, I'll go this way, creating a class with ClassificationID and Level (not inheriting from anything) and see what I come up with. Thanks!
HardCode
I was just thinking. My real object isn't "Customer" (just a simplified example). The real object is going to be composed of many objects that also have a "master list" This means I'll have to make a new, second class for *every* master list object that will be used to compose the real object?
HardCode
Essentially yes. However, you should really think in terms of responsibilities separation. One of the classes is responsible for maintaining the list elements. The other is just a small wrapper around the value from the list.
Franci Penov
Great. Thanks for the info. I just wanted to make sure I wasn't needlessly duplicating efforts.
HardCode