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