views:

59

answers:

4

I'm in a project where it's pretty much my first time doing all the architecture myself, and I'm running into a frustrating situation. My architecture for forms seems to be correct from a heuristic perspective, but I don't think its implementation is correct.

My architecture is thus:

Base Class: OrderForm

Child Classes: PurchaseOrder, Invoice, Credit

Child Class of PurchaseOrder: StockingOrder

Architecturally this makes sense (to me) because all the child classes are OrderForms ("is a") and a Stocking Order "is a" Purchase Order, just a special kind.

PROBLEM

While coding my StockingOrder class, I've noticed that I've had to Shadow most if not all of the methods I want to use from PurchaseOrder since they conceptually do the same thing but require slightly different implementation functionality. This, of course, smells to me, but I don't know how to fix it. What am I doing wrong? Or is this normal?(!)

Thanks...

+3  A: 

It sounds like you might need some virtual methods in PurchaseOrder. Maybe something like the following:

public abstract class OrderForm
{
    //orderform members
}

public class PurchaseOrder: OrderForm
{
    public void DoSomething()
    {
        //some logic that can be reused by child classes
        DoSomethingElse();
    }

    protected virtual void DoSomethingElse()
    {
        //specialized logic
    }
}

public class StockingOrder: PurchaseOrder
{
    protected override void DoSomethingElse()
    {
        //specialized logic that makes StockingOrder different than PurchaseOrder
    }
}

This should help to reuse more code as you could group the similar logic you are writing in the PurchaseOrder DoSomethingMethod while keepin the specialized logic (that is different between PurchaseOrder and StockingOrder) in your virtual DoSomethingElse method.

Matt Dearing
I just saw that you tagged your question VB.NET. Hopefully this can still help.
Matt Dearing
i understand C# too, so this is fine. i see what you're doing, but this also kind of smells, doesn't it? maybe i don't really know what smells and what doesn't?
Jason
thank you, (i believe) this is what i need! :)
Jason
additionally: thank you for showing me the correct (and arguably better) way to look at the creation of reusable methods! this is making things loads easier :)
Jason
additionally additionally: do you have some sort of naming convention for these "specialized logic" methods? for instance, if i have a method called `FillForm()`, what would you call a method that has a little bit of specialized logic called in that method? THANKS!
Jason
There would be no set rule, that I am aware of, for naming these methods, like you wouldn't want to call it FillFormSpecializedVirtual or anything like that. You should name it just like you would any other method. You just want the name to be short and to the point of its functionality.
Matt Dearing
+1  A: 

As mdearing06 suggested, you should use virtual methods (or just overridable methods) and override them. Using Shadowing to change the functionality of your own code is somewhat of a bad practice. Shadowing is meant to be used in uncommon scenarios, i.e.: when you inherit from a class that was written by someone else and you must change some of its functionality, but can't view/edit the code itself.

Consider the fact that Shadowing is much like Overloading (only that it hides the base implementations), and quite different than Overriding. The shadowing method will only be called if you explicitly refer to the object by its class; otherwise, the original method will be called (unlike Overriding, where the method is called based on the content - not on the representation - of the referenced object).

Here is an example of how representation affects a shadowed method's invokation:

Class BaseClass
    Public Sub MyMethod()
        Trace.WriteLine("The original method")
    End Sub
End Class
Class ShadowClass
    Inherits BaseClass
    Shadows Sub MyMethod()
        Trace.WriteLine("The shadowing method")
    End Sub
End Class
Class Tester
    Public Shared Sub TestClasses()
        Dim myObj As Object = New ShadowClass
        Dim var0 As BaseClass = myObj
        var0.MyMethod()
        Dim var1 As ShadowClass = myObj
        var1.MyMethod()
    End Sub
End Class

After running Tester.TestClasses, the trace will show: "The original method", followed by "The shadowing method".

Now, if we use the following code instead:

Class BaseClass
    Public Overridable Sub MyMethod()
        Trace.WriteLine("The original method")
    End Sub
End Class
Class OverridingClass
    Inherits BaseClass
    Overrides Sub MyMethod()
        Trace.WriteLine("The overriding method")
    End Sub
End Class
Class Tester
    Public Shared Sub TestClasses()
        Dim myObj As Object = New OverridingClass
        Dim var0 As BaseClass = myObj
        var0.MyMethod()
        Dim var1 As OverridingClass = myObj
        var1.MyMethod()
    End Sub
End Class

The Trace output will display "The overriding method", followed by "The overriding method".

To sum, I'd say that overriding is the "normal" way, and shadowing is an anomaly.

M.A. Hanin
i see what you are saying, but i don't know that i would ever encounter the scenario you're describing above... my question is basically, when you inherit a class, do you spend a lot of time overriding the methods? doesn't that kind of defeat the purpose of inheritance? i mean some (hopefully most) things can be reused, but there will always be lots (if not all) methods that need to be rewritten just because your specialized object can't functionally perform what its parent does because of minor differences... right..?
Jason
@Jason, functionality should be divided into smaller blocks, and only the parts that behave differently should be overriden. If this division is done correctly, overriding methods should be simple and straightfoward, and shouldn't make you work harder but rather easier!If the entire implementation is different, then an Interface or an abstract class should be used.In some way, I think that you're confusing OOD's power with a weakness.This discussion is outside the scope of a SO question, and should be continued over a forum where your specific scenario can be analyzed and commented.
M.A. Hanin
A: 

I would recommend taking a look at the Strategy Pattern. This will allow you to give each order type the "playbook" for the method(s) your are executing. This will help you simplify the variance in the logic.

Adam Fyles
A: 

Another option is to use interfaces; set-up code contracts that allow you to program aganist a defined interface without having to worry about the impmentation underneath.

This also allows you to define multiple interfaces that focus on specific tasks, this allows your code to be much more maintainable and flexible.

Then, for common methods, put them in a helper class that your implementations can leverage off.

Check these out for more reference :)

http://www.developer.com/lang/other/article.php/939411/Implementing-Interfaces-in-VB-NET.htm

http://blogs.msdn.com/trobbins/archive/2004/08/26/221241.aspx

Adrian K
thanks for the links... the problem isn't solved by interfaces though if `StockingOrder` inherits `PurchaseOrder`, which would implement whatever interface. I'd still have to override/shadow the declared methods :\ right?
Jason