Home > database >  Abstract class implementation design
Abstract class implementation design

Time:02-18

Currently I have made a design where my BaseClass is the guideline of how my program has to behave. I have made an abstract method DoWork() , the inheritors have to implement this method.

The thing is Class C overrides Setup() so it doesn't need DoWork() anymore. Now I am left with a throw new NotImplementedException();

Question: Is there a way how to improve my design so I won't have those methods with NotImplementedException?

public abstract class BaseClass
{
    public virtual void Setup()
    {
        DoWork();
        FinnishWork();
        Environment.Exit(0);
    }

    public abstract void DoWork();
    public abstract void FinnishWork();
}

public class A : BaseClass
{
    public override void DoWork()
    {
        Console.WriteLine('A');
    }
    public override void FinnishWork()
    {
        Console.WriteLine('FinnishA');
    }
}

public class B : BaseClass
{
    public override void DoWork()
    {
        Console.WriteLine('B');
    }
    public override void FinnishWork()
    {
        Console.WriteLine('FinnishB');
    }
}

public class C : BaseClass
{
    public override void Setup()
    {
        FinnishWork();
        Console.WriteLine('C');
    }

    public override void DoWork()
    {
        throw new NotImplementedException();
    }

    public override void FinnishWork()
    {
        Console.WriteLine('FinnishC');
    }
}

CodePudding user response:

You're inheriting in too few steps. You need BaseClassLite and BaseClassHeavy to make this work.

Start with this:

public abstract class BaseClassLite
{
    public virtual void Setup()
    {
        FinnishWork();
        Environment.Exit(0);
    }

    public abstract void FinnishWork();
}

public abstract class BaseClassHeavy : BaseClassLite
{
    public override void Setup()
    {
        DoWork();
        base.Setup();
    }

    public abstract void DoWork();
}

(Or give them more meaningful names.)

Then you implement your classes like this:

public class A : BaseClassHeavy
{
    public override void DoWork()
    {
        Console.WriteLine("A");
    }
    
    public override void FinnishWork()
    {
        Console.WriteLine("FinnishA");
    }
}

public class B : BaseClassHeavy
{
    public override void DoWork()
    {
        Console.WriteLine("B");
    }
    public override void FinnishWork()
    {
        Console.WriteLine("FinnishB");
    }
}

public class C : BaseClassLite
{
    public override void Setup()
    {
        base.Setup();
        Console.WriteLine("C");
    }

    public override void FinnishWork()
    {
        Console.WriteLine("FinnishC");
    }
}

CodePudding user response:

As class C doesn't implement DoWork() it shouldn't really inherit from your abstract class.

You can only inherit from one class, but you can implement many interfaces. In many ways it is simpler to deal with interfaces than abstract classes. Base classes, whether abstract or not really come into their own if they perform some function that you may wish to provide to you inheriting classes. An abstract class with empty methods isn't any better than an interface. Consider something like:

public interface IDoWork
{
    void DoWork();
}

public interface IBase
{
    void Setup();
    void FinnishWork();
}

public abstract class BaseClass : IBase, IDoWork
{
    public virtual void Setup()
    {
        DoWork();
        FinnishWork();
        Environment.Exit(0);
    }

    public abstract void FinnishWork();

    public abstract void DoWork();
}

public class A : BaseClass
{
    public override void DoWork()
    {
        Console.WriteLine('A');
    }
    public override void FinnishWork()
    {
        Console.WriteLine("FinnishA");
    }
}

public class B : BaseClass
{
    public override void DoWork()
    {
        Console.WriteLine('B');
    }
    public override void FinnishWork()
    {
        Console.WriteLine("FinnishB");
    }
}

public class C : IBase
{
    public void Setup()
    {
        FinnishWork();
        Console.WriteLine('C');
    }

    public void FinnishWork()
    {
        Console.WriteLine("FinnishC");
    }
}

Examples in use:

IBase instanceA = new A();
BaseClass instanceB = new B();
IBase instanceC = new C();

instanceA.Setup();
instanceB.Setup();
instanceC.Setup();

instanceB.DoWork();

CodePudding user response:

Use a second base class to be inherited from class C:

public abstract class BaseBaseClass
{
    public virtual void Setup()
    {
        FinnishWork();
        Environment.Exit(0);
    }
    ...
}
public abstract class BaseClass : BaseBaseClass 
{
    public abstract void DoWork();
    ...
}
public class C : BaseBaseClass {...}

CodePudding user response:

The idea to have a Setup method in BaseClass while having 2 abstracts methods to implement is good (it is even given a name: template method pattern).

However there is one problem lying in how Setup() is declared in BaseClass: you made it virtual which goes against the principle that you want to enforce:

BaseClass is the guideline of how my program has to behave

It is now possible to override it (like you did in C) and break the behavior you want to enforce.

First, remove virtual in BaseClass then override DoWork in C as follow:

public override void DoWork() { }

Having this kind of empty method is a sign of a flawed abstraction (does C really need to inherit from BaseClass ?) but I can't help more if you don't provide more context about the real meaning and names of these classes/methods.

  • Related