Inheritance vs Composition (.Net approach)

Inheritance vs Composition (.Net approach)

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


aporter posted on Saturday, August 01, 2009

Referring to Inheritance vs Composition approaches in coming up with a good OO design I believe that the issue is not really relevant in .Net.

I think one can still use inheritance without the disadvantage of fragile coupling. The secret to this is one nice keyword "NEW" which allows a class author to break inheritance for a single method and allows him to overrride that method even using different return types etc.

What does this mean? If the BaseClass author changes a method signature (thus creating problems for any client code using inherited subclasses) all that needs to be done is to implement the old method using the NEW keyword directly in the affected subclasses. All client code will be oblivious to any changes thus taking place internally in both subclass and baseclass.

Like this you have all the advantages of inheritance without incurring tight and fragile coupling problems. Am I missing something in all this?

I am posting an example hereunder (based on another example courtesy of Bill Venners) to illustrate better what I mean. I have examples introducing an interface change using both composition and inheritance. The return type for method Peel (in the baseclass) is changed from int to a double. Note that using Inheritance we can still hide the change to outside client code.

Appreciate opinions on this matter. In my example hereunder I have 4 regions

1. Inheritance Before Change

2. Inheritance After Change

3. Composition Before Change

4. Composition After Change

___________________________________

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            /**Relationship through Inheritance. Before Change***/
            Apple a = new Apple();
            int i = a.Peel();
            System.Console.WriteLine(i);

            /**Relationship through Inheritance. After Change***/
            AppleB ab = new AppleB();
            int j = ab.Peel();
            System.Console.WriteLine(j);

            /**Relationship through Composition. Before Change***/
            AppleC ac=new AppleC();
            int k=ac.Peel();
            System.Console.WriteLine(k);

            /**Relationship through Composition. After Change***/
            AppleD ad = new AppleD();
            int l = ad.Peel();
            System.Console.WriteLine(l);
        }
    }

 

    #region Inheritance Before Change

    class Fruit
    {
        public virtual int Peel()
        {
            return 0;
        }
    }

    class Apple:Fruit
    {
       
    }

    #endregion

    #region Inheritance After Change

    class FruitB
    {
        public virtual double Peel()
        {
            return 0;
        }
    }

    class AppleB : FruitB
    {
        public new int Peel()
        {
            return Convert.ToInt32(base.Peel());
        }
    }

    #endregion

 

    #region Composition Before Change

    class FruitC
    {
        public virtual int Peel()
        {
            return 0;
        }
    }

    class AppleC
    {
        FruitC f = new FruitC();

        public int Peel()
        {
            return f.Peel();
        }
    }


    #endregion

    #region Composition After Change

    class FruitD
    {
        public virtual double Peel()
        {
            return 0;
        }
    }

    class AppleD
    {
        FruitD f = new FruitD();

        public int Peel()
        {
            return Convert.ToInt32(f.Peel());           
        }
    }


    #endregion


 


}

 

 

RockfordLhotka replied on Saturday, August 01, 2009

The problem with shadowing (which is what you are talking about) is that it is not polymorphic and has different semantics from virtual methods.

A virtual method works regardless of the type of variable pointing to the object. The variable could be of the base class type or the subclass type, but the behavior is always the same.

A shadowed method is entirely dependent on the type of variable pointing to the object. If the variable is of the base class type, the base class implementation is called. If the variable is of the subclass type, the shadowed subclass implementation is called.

So using shadowed methods is tricky, because the calling code needs to make sure to use the right type of variable to make the call, or they'll end up calling the wrong implementation.

ajj3085 replied on Monday, August 03, 2009

This is one .Net feature I wish they'd left out.

Copyright (c) Marimer LLC