Dion V.
Dion V.

Reputation: 2120

How to correctly interface an existing sealed class?

After having my code being reviewed on CodeReview, I am stuck on the question how to make my piece of code more abstract.

As you can see in here, many suggest that I should create an ICommand and IConnection interface to make it easier to refactor.

In my examples I will only use IConnection, but the whole should also be valid for ICommand.

I figured I would have to create an interface like this;

public interface IConnection
{
     //etc...
}

And then, to make the MySqlConnection be able to inherit from my IConnection, I would have to create my own MySqlConnection which would inherit like this;

public class MySqlConnection : MySql.Data.MySqlClient.MySqlConnection, IConnection
{
     //etc...
}

Which would mean the new MySqlConnection would still have its methods and fields, and would inherit from IConnection. I should then be able to write a Database class like this;

public abstract class Database
{
    protected IConnection con;
}

And extend it like this;

public class MySqlDatabase : Database
{
    private override IConnection con = new MySqlConnection();
}

Now, my problem is, MySqlConnection is sealed; I can't extend it and therefore I do not know any option to make this database class abstract.

The question is; is there a proper way to implement the abstraction of Database and if yes, how would I do it?

Please note that this question has nothing to do with the class being a singleton (as shown in my CodeReview post). That problem has been issued and is not relevant to the question.

Upvotes: 2

Views: 2197

Answers (2)

steavy
steavy

Reputation: 1576

What about implementing decorator pattern:

interface IConnection
{
    string ConnectionString {get; set;} // Define your interface explicitly
}

Then you can create a class like this:

class MySqlDbConnection : IConnection
{
    private MySql.Data.MySqlClient.MySqlConnection connection;

    public MySqlConnection(MySql.Data.MySqlClient.MySqlConnection connection)
    {
        // Check for null
        this.connection = connection;
    }

    #region Implementation of IConnection
    public ConnectionString
    {
        get
        {
            return connection.ConnectionString; // Not sure if this is the right name of property
        }
        set
        {
            connection.ConnectionString = value;
        }
    }
    #endregion
}

So what do you achive like this:

1) you can explicitly expose those fields of Connection class that you really need

2) you still can make initial configuration at the stage of initialization of your concrete Database class

3) and your code becomes some kind of more abstract

4) and what is very convenient - if connections for different databases (f.e. mysql/sqlite and so on) will have different names of connectionString field - then you can wrap them with your single property, defined by your interface. What I mean - you are the one to rule the situation, and inheritance might limit you at this point.

Anyway, before starting to implement something, try to describe everything with interfaces and only then implement classes.

Upvotes: 0

C.Evenhuis
C.Evenhuis

Reputation: 26446

Reading the comments on that code review, I actually think they meant use IDbConnection and IDbCommand instead of rolling your own. All ADO.NET providers already implement those.

However if you want you could inherit from DbConnection and IConnection and wrap the MySqlConnection. You'd have to implement all DbConnection methods and relay them to the wrapped connection:

public sealed class MyMySqlConnection : DbConnection, IConnection
{
    public MyMySqlConnection(MySqlConnection underlyingConnection)
    {
        UnderlyingConnection = underlyingConnection;
    }

    public MySqlConnection UnderlyingConnection
    {
        get;
        private set;
    }

    public override void Open()
    {
        UnderlyingConnection.Open();
    }

    // ...

Upvotes: 4

Related Questions