Generics and Inheritance Redux

Generics and Inheritance Redux

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


bgilbert posted on Tuesday, February 09, 2010

Sorry if my questions have been answered before. I've pored over the forums for a couple of days and still cannot get my head around this stuff.

I have a WinForms app that is currently written with one client in mind. I'm now working on extending it for my second client. 80-90% of the functionality will be the same between the two clients, but several UI and business layer elements will need to be different.

To illustrate my confusion, in the business layer, I currently have these classes defined:

<Serializable(), _

TypeDescriptionProvider(GetType(ProdOrderDescriptionProvider))> _

Public Class ProductionOrder: Inherits KzBusinessBase(Of ProductionOrder)

and

<Serializable()> _

Public Class ProductionOrders :Inherits KzBusinessListBase(Of ProductionOrders, ProductionOrder)

You can see that I have two base classes that inherit from CSLA BusinessBase(Of T) and BusinessListBase(Of T,C). Also, I'm using ITypedList to expose "virtual" properties to the UI.

Now I need a ProductionOrderClient2 class to extend the functionality (methods, properties, rules, etc.). I don't really need polymorphism because the UI will likely have client-specific forms that will only need to use a single slice of these objects. So, I assume I can use a client-specific collection class. I'd change ProductionOrder to a generic like this:

Public MustInherit Class ProductionOrder(Of T As ProductionOrder(of T) : Inherits KzBusinessBase(Of T)

and the collection class to this:

Public Class ProductionOrdersClient2:  Inherits KaizenBusinessListBase(Of ProductionOrdersClient2, ProductionOrderClient2)

and not attempting to inherit from a ProductionOrders abstract class. I think I need to make ProductionOrder generic to allow it to be contained in ProductionOrdersClient2.

I have a shared factory method that, based on a ClientContext object, returns the specific sub-type.

My goals here are to leverage as much existing code as possible/practical and to make it easier to add Client 3 down the road.

I have several concerns at this point.

1-How do I deal with all the code throughout my business layer that contains ProductionOrder objects. If ProductionOrder is declared as abstract, don't I need to somehow know which subclass type is being used in every declaration? I've seen comments in the forum that suggest that one should use concrete classes as high up in the hierarchy as possible. However, I cannot figure out how to use inheritance to inherit from ProductionOrder/ProductionOrders. If I use a common collection class, then ProductionOrder needs to also be generic, right? If I use new, standalone collection classes that are strongly-typed to use the new derived classes, then I'm... uh...lost. Head spinning...walking in circles.... mumbling incoherently.... Coworkers say "He must be working on OO design stuff again".

Would it be best to not use inheritance, but to create an IProductionOrder interface? If so, I'll end up having a ton of duplicated code. I could, conceivably, move some of this code (maybe rule methods) into another class. But, like I said, I'm not concerned about polymorphism because I'll never have a mix of subclass objects within the same app instance.

I'm really open to any help you can offer and would be willing to look at design patterns that might help. I really don't want to take the easy path and regret it for years to come.

 

Thanks,

Barry

RockfordLhotka replied on Friday, February 12, 2010

bgilbert

Would it be best to not use inheritance, but to create an IProductionOrder interface? If so, I'll end up having a ton of duplicated code. I could, conceivably, move some of this code (maybe rule methods) into another class. But, like I said, I'm not concerned about polymorphism because I'll never have a mix of subclass objects within the same app instance.

Generally yes, you should favor composition (and normalization of behavior) over inheritance. That's an often repeated phrase in OO books, training, etc. In short it means that inheritance is rarely the right answer because it incurs tight coupling and reduces maintainability.

The code that gets duplicated in most cases are property declarations - those 4-5 lines of code created using a snippet or code generator. I don't count those as "code", and instead view them as the definition of the shape of my object.

Real code, like business rules, should exist in rule methods. Those can be externalized and normalized so they aren't repeated. Sure, you attach the rule to different objects, but the rule implementation (the part that really matters for maintainability) exists only once.

bgilbert replied on Friday, February 12, 2010

So if I understand your advice, I would create an IProductionOrder interface that defines my common properties and any other methods that need different behaviors for each implementation. Then the classes that implement the interface would call common shared methods in a helper class (things that I might have originally put in my base class). I'd also have to duplicate things like data portal methods and factory methods. Or would I create an object factory class that creates different objects based on my client context configuration? Also, these classes would inherit directly from my BusinessBase classes, right?

 

This sounds much more manageable than trying to use inheritance, where I could see months of hair pulling trying to figure out data binding voodoo.

 

Thanks for your help.

RockfordLhotka replied on Friday, February 12, 2010

You'd only create an interface if you need polymorphic behavior (like creating a heterogeneous list or something). Remember that no data binding technologies use interfaces, so they are really quite useless unless you personally need them in your code.

If these types are similar enough in terms of the data they contain, then having some common DAL code is probably good. If they are quite different, then you may not be able to have common DAL code. There are four primary DAL models supported by CSLA - you can get info on them in Chapter 18 and/or in the Core 3.8 video series.

bgilbert replied on Friday, February 12, 2010

I don't need polymorphic collections here, but I do need to contain these two types of objects in other classes. For example, I have ProductionOrderClient1 and ProductionOrderClient2. In another class, let's call it SalesOrder, I currently store either individual or collections of one of these two types. Instead of creating SalesOrderClient1 and SalesOrderClient2 to deal just with the ProductionOrder differences, I can have a single SalesOrder class that contains instances of IProductionOrder. Is this right? Is this an example of the value of an interface if I don't need polymorphism?

Copyright (c) Marimer LLC