Subclassing: How to Plumb

Subclassing: How to Plumb

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


WyattRidesAgain posted on Saturday, November 04, 2006

I'm getting up to speed on CSLA and am a relative OO novice.  In trying to design various parts of my application I keep coming up with a pattern for which I cannot figure out a CSLA solution.  The pattern is:

 - Root CSLA biz object, composed of one or more child CSLA biz objects and/or collections that implement behaviors specific to the root object.

 - Subclassed CSLA biz objects, which add behaviors to the root biz object and inherit the behaviors of the root object via its child objects/collections.

To give a concrete example, assume the root object is "Entity".  It holds a child collection "Roles", which holds one or more objects like "Customer", "Vender", etc.  Entity is subclassed into either "Individual" or "Organization".  The goal is that Individual or Organization inherits the Entity Role behaviors related to Customer and/or Vender and/or etc. 

I've read many posts in the forum about related topics on using inheritance, composition, generics, and interfaces.  While I understand much of it on an abstract level, when I try to write real code I keep hitting roadblocks.  My head is swirling and my brain hurts.  I think I'm missing the elephant in the room.

Could someone give a concrete example of how the various CSLA objects might be set up?

Thanks,

Wyatt

 

guyroch replied on Saturday, November 04, 2006

Here's a c# code sample on how to inherit from your base class...

[Serializable()]
public abstract class MyAppBusinessBase<T> : BusinessBase<T>
      where T : MyAppBusinessBase<T>
{   
    // Base Class


}

---------------

[Serializable()]
public sealed partial class MyBizObjectBO : MyAppBusinessBase<MyBizObjectBO>
{
     // Business Object Class which Inherits your base class
}

 

Hope this helps

Bayu replied on Sunday, November 05, 2006

So, if I understand you correctly you have the following forces on your design:
- both individuals and organization can be assigned roles, so you want a base class that provides exactly this (Entity)
- but other than that they each have specific behavior, which causes you to make specific subclasses


To make this work, I believe all you would have to do is the following:
- create a member on your child collection class which takes a ISafeDataReader (or something akin like a DataTable or DataSet, whatever works for you) and then populates the collection for you from the supplied data object
- on Entity you define a property that holds such a collection (e.g. Roles)
- in the dataportal_fetch of both Individual and Organization you would invoke the aforementioned member with the correct argument(s) in order have it load the Roles
- the remainder of your dp_fetch members in those subclasses deal with loading the specific class

See also www.onelittlevictory.com for additional help on this, also on how to get the other CRUD operations to work.

What you achieved then is that you can load, update and save your objects.


The next thing that you hit into then will be that you want to alter/extend/enhance behaviors in your specific sub-classes. Several techniques (design patterns) exist to address these kinds of challenges, but 'template methods' are usually preferred:

- declare a method in your base class (Entity) as overriddable, you can leave it empty or you provide a default implementation in your base class. In your sub-class you then override this method, depending on your use case you can then call the base implementation via MyBase.<methodname> or you decide to fully replace the default implementation with a new one (so don't call the base class' implemenation).

- sometimes you have routines in your base class that strongly rely on specifics that your subclass must provide. Then you can also choose to define MustOverride members in your base class. You can invoke them as usual in your base-class routines, but you leave the actual implementation to the sub classes. Basically, with MustOverride you force sub-classes to provide an implementation, whereas with overridable you gently allow this.

Many more techniques exist. If you need more advice, then you may perhaps better outline the details of the brick wall you hit into.

Regards,
Bayu

WyattRidesAgain replied on Monday, November 06, 2006

Bayu and guyroch,

Thanks very much for your advice;  you've given me new energy to try again.  Let me work on it and see if I can get it to work.  Will let you know how it goes.

Wyatt

guyroch replied on Monday, November 06, 2006

Here's another helpful link...

http://www.primos.com.au/primos/Articles/CSLAversion2whatsinitforme/tabid/67/Default.aspx

WyattRidesAgain replied on Monday, November 06, 2006

I'm stuck trying to design the Role editable child, which would be held by Entity via its Roles collection property.  Assuming the parent Entity is designed like guyroch suggests:

public abstract class Entity<T> : Csla.BusinessBase<T> where T : Entity<T> { //base code }

then for CRUD data access how does the child Role reference Entity, which presumably is its parent?  To use Insert as an example, I've tried:

internal void Insert(SqlConnection cn, Entity<T> parent)  { // data access code here }

..but the compiler doesn't like "Entity<T>".  I've tried other variations to reference Entity, but they all create compiler errors.

I know I'm doing something wrong here.  Any ideas?

 

Thanks,

Wyatt

 

 

Bayu replied on Monday, November 06, 2006

Hey Wyatt,

To make this work, I guess you would need to define your roles collection as follows:

(sorry, I am a VB guy, so you will need to translate this)

<Serializable()> _
Public Class Roles(Of TParent As Entity(Of TParent)
    Inherits BusinessListBase(Of Roles, Role)


In your Insert member you could then do the following:

Friend Sub Insert(conn as SqlConnection, parent As TParent)


This will have some repercussions on your other code, I cannot oversee if this will cause you more trouble or whether this is going to lead to a solution for you.

Hope this helps.

Bayu

WyattRidesAgain replied on Wednesday, November 08, 2006

Bayu and guyroch,

After much trial and error and pain, I finally got it working.  I've learned a bit about generics in the process, though a fair amount of it still mystifies me.  Many thanks for your help!

Having gone through this now, I'm curious to get your insight on something.  I'm trying to use code generation (ala Ricky Supit's CodeSmith tool at Codeplex) for my business objects.  I now see that using using inheritance involves a lot of hand-coding on the objects;  at least it did for me.  In addition to the OO mantra of preferring composition over inheritance, is there some truth that using composition in CSLA is more "codegen friendly" than using inheritance?

Wyatt

guyroch replied on Wednesday, November 08, 2006

Glad to see you up and running... can you please post your working code for everybody to see :)  It would be good for future readers.

Thanks 

WyattRidesAgain replied on Thursday, November 09, 2006

GuyRoch,

Glad to contribute; thanks for asking. Attached is a zip file with four classes I built to figure out how to use inheritance as described in this thread. The classes' members and behaviors are as simple as possible, since my focus was on how to implement generics. Class overview:

Role:

- Inherits from Csla.BusinessBase

- Has one string business property, RoleName, which would hold values like "vendor", "customer", "employee", etc.

Roles:

- Inherits from Csla.BusinessListBase

- Child to Party (see below)

- Holds the Role objects

Party:

- ("Party" is replacement name for "Entity" used earlier in the thread)

- Is abstract; inherits from BusinessBase

- Has one business property, PartyType, which holds a string value like "Person" or "Organization", describing what kind of Party it is.

- Holds a reference to Roles

Person:

- Inherits from Party, and therefore inherits Roles behavior/information

- Has one business property, FirstName

Again, the class methods are deliberately trivial since I was struggling getting generics to work. In the end it finally did, though I have to admit to being mystified by some of it.

As a question to pose to the group: Is there a way to avoid using generics with Roles and Role? Doing so seems to force client code to have to reference the concrete class, which isn't particularly intuitive to the user of the Role object. It looks like this:

_role = Role<Person>.NewRole(); // not intuitive

It would be nice to be able to simply use:

_role = Role.NewRole(); // intuitive

Thanks,

Wyatt

Copyright (c) Marimer LLC