C#, interfejs, klasa abstrakcyjna

0

Cześć.

Chciałbym tylko poprosić Was o zweryfikowanie tego czy dobrze rozumiem mechanizmy interfejsów, klas abstrakcyjnych oraz polimorfizmu.

Staram się ogarnąć różnice pomiędzy interfejsami a klasami abstrakcyjnymi - być może błahy temat, ale potrzebuje potwierdzenia od kogoś z doświadczeniem.

Napisałem przykładowy kod, który symuluje operacje na bazie danych. W przykładzie chciałem mieć możliwość obsługi połączenia z różnymi bazami (MSSQL, SQLite, Oracle).

Tak wygląda kod oparty na interfejsie:

    class DB
    {
        protected IDBConnection connection;

        public void Initalize()
        {
            connection = new DBMSSQL();
            connection.connect("localhost");
        }
    }

    public interface IDBConnection
    {
        bool connect(string hostName);
    }

    public class DBMSSQL : IDBConnection
    {
        public bool connect(string hostName)
        {
            Console.WriteLine("Connecting to the MSSQL DB using following host name : {0}", hostName);

            return true;
        }
    }

    public class DBOracle : IDBConnection
    {
        public bool connect(string hostName)
        {
            Console.WriteLine("Connecting to the Oracle DB using following host name : {0}", hostName);

            return true;
        }
    }

    public class DBSQLite : IDBConnection
    {
        public bool connect(string hostName)
        {
            Console.WriteLine("Connecting to the SQLite DB using following host name : {0}", hostName);

            return true;
        }
    }

Natomiast tutaj mam kod oparty na klasie abstrakcyjnej:

    class DB
    {
        protected DBConnection connection;

        public void Initalize()
        {
            connection = new DBMSSQL();
            connection.connect("localhost");
        }
    }

    public abstract class DBConnection
    {
        private int connectionPort;

        public int ConnectionPort
        {
            get
            {
                return connectionPort;
            }

            set
            {
                if (value <= 0)
                    connectionPort = 999;
                else
                    connectionPort = value;
            }
        }

        public abstract bool connect(string hostName);
    }

    public class DBMSSQL : DBConnection
    {
        public override bool connect(string hostName)
        {
            Console.WriteLine("Connecting to the MSSQL DB using following host name : {0}", hostName);

            return true;
        }
    }

    public class DBOracle : DBConnection
    {
        public override bool connect(string hostName)
        {
            Console.WriteLine("Connecting to the Oracle DB using following host name : {0}", hostName);

            return true;
        }
    }

    public class DBSQLite : DBConnection
    {
        public override bool connect(string hostName)
        {
            Console.WriteLine("Connecting to the SQLite DB using following host name : {0}", hostName);

            return true;
        }
    }

Poprawcie mnie proszę jeśli mylę się w którymś z punktów lub jeśli coś pominąłem.

1. Polimorfizm

Rozumiem, że w obu przypadkach mam do czynienia z polimorfizmem ponieważ mam elastyczność w kwestii wyboru obiektu na rzecz którego wywołana zostanie metoda connect, której zadaniem będzie realizacja połączenia z wybranym typem bazy danych. Dzięki temu w trakcie wykonywania programu mogę zdecydować jakiego typu połączenia użyć. Dodatkowo rozwiązanie takie stanowi zaletę przy pracy w zespole, ponieważ programista otrzymuje interfejs, nie musi przejmować się jak metoda została zaimplementowana tylko jej używa wedle uznania.

2. Różnice

Różnica pomiędzy interfejsem a klasą abstrakcyjną polega na tym, że w przypadku klasy abstrakcyjnej mam jeszcze możliwość zdefiniowania "dodatkowej" logiki jak w przypadku property ConnectionPort. Mogę również zdefiniować metody nie abstrakcyjne.

3. Podobieństwa

Tak jak w pierwszym punkcie, oba przypadki zapewniają elastyczność oraz w obu przypadkach nie da się utworzyć instancji obiektu dla interfejsu IDBConnection ani dla klasy abstrakcyjnej DBConnection.

4. Kiedy stosować?

Możecie mi wytłumaczyć kiedy lepiej stosować interfejsy a kiedy klasy abstrakcyjne? Czy też sam sobie już odpowiedziałem na to pytanie w punkcie 2 - możliwość definiowania metod w ciele klasy abstrakcyjnej. Czy też jest to uzależnione ściśle od specyfiki realizowanego projektu?

Będę wdzięczny za pomoc.

Pozdrawiam

2

Generalnie stosuj interfejsy. Mają tę przewagę, że klasa może dziedziczyć od kilku interfejsów ale nie może dziedziczyć od kilku innych klas, ponieważ w C# nie ma wielodziedziczenia klas tak jak np. w C++. Poza tym dziedzicząc od interfejsu nie musisz używać base, bo interfejsy nie mają konstruktorów. To po prostu prostsze podejście.

Naturalnie jeżeli musisz zrobić jakieś drzewo dziedziczenia np: Person jest klasą, od której dziedziczą Student i Driver to lepiej zrobić z klasy Person abstrakta.

3

Interfejsy służą do czegoś więcej niż dziedziczenie. Interfejs definiuje pewne zachowania i klasa je implementująca deklaruje te zachowania. Weźmy dla przykładu IDisposable. Jeżeli klasa go implementuje, to wiadomo, że przy zakończeniu pracy z jej obiektem należy wywołać metodę Dispose(). Innym przykładem jest interfejs IEnumerable, który deklaruje, że obiekt posiada elementy po których można iterować.

Klasa abstrakcyjna jest to klasa bazowa, której obiektów tworzyć po prostu nie ma sensu. To tak w skrócie.

0

Dziękuję za Wasze odpowiedzi.

W takim razie będę trzymał się interfejsów, ewentualnie w szczególnych przypadkach zwrócę się w stronę klas abstrakcyjnych.

Pozdrawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1