C# – Is it ok to have an empty abstract class to make concrete classes polymorphic

cinheritanceinterfacesobject-orientedpolymorphism

BEFORE:

I have an interface that has one method definition

public interface IDockable
{
    void Dock(DockerContainerConfig config);
}

Everything is ok for my first implementation

public class DockerContainer : IDockable
{
    public void Dock(DockerContainerConfig config)
    {

    }
}

public class DockerContainerConfig
{ 
    //machine configuration properties here 
}

On my second implementation however, I realized that I need to use a different set of configuration.

public class DockerMachine : IDockable
{
    public void Dock(DockerMachineConfig config)
    {

    }
}

public class DockerMachineConfig
{
    //machine configuration properties here 
}

AFTER:

In order to make the Configuration Classes polymorphic, I created a parent class and let the Configuration Classes inherit from it.

public class DockerConfig
{

}

public class DockerMachineConfig : DockerConfig
{
    //machine configuration properties here 
}

public class DockerContainerConfig : DockerConfig
{
    //container configuration properties here 
}

With this I also changed the method definition for the interface.

public interface IDockable
{
    void Dock(DockerConfig config);
}

And in my concrete classes, I just did a cast on the configuration class objects. Please note that the two configuration classes are totally different, nothing is common. One deals with the machine so it needs machine configuration and the other deals with the container so it needs container configuration. But either way you do it, DockerContainer and DockerMachine does the same thing. "dock a container inside a machine". It's something like DockerMachine does things from the outside and DockerContainer does things from the inside. You get the idea 🙂

public class DockerContainer : IDockable
{
    public void Dock(DockerConfig config)
    {
        DockerContainerConfig container = config as DockerContainerConfig;
    }
}

public class DockerMachine : IDockable
{
    public void Dock(DockerConfig config)
    {
        DockerMachineConfig machine = config as DockerMachineConfig;
    }
}

There are two things that I think I made a mistake here:

  1. I changed the method definition in my interface from void Dock(DockerContainerConfig config); to void Dock(DockerConfig config);
  2. I created an empty parent class public class DockerConfig{} just to be able to make my Configuration Classes polymorphic

I would like to know if the changes I made conforming to good design and best practices.

Best Answer

public interface IDockable<T>
{
    public void Dock(T config);
}

By having a type parameter, you can specify the parameter you want to accept within the Dock method in your classes. Example:

public class DockerMachine : IDockable<DockerMachineConfig>
{
    public void Dock(DockerMachineConfig config)
    {
    }
}

public class DockerContainer : IDockable<DockerContainerConfig>
{
    public void Dock(DockerContainerConfig config)
    {
    }
}

That would be my personal preferred way to do this, but there are plenty of other ways which you'll be able to come up with. What you're currently doing could definitely be simplified by having a type parameter on the IDockable interface which would be a little bit cleaner in my opinion.