Абстрактните класове приличат на интерфейсите по това, че те не могат да се инстанцират, защото могат да съдържат дефиниции на неимплементирани методи, но за разлика от интерфейсите могат да съдържат и описани действия. Абстрактният клас реално е комбинация между клас и интерфейс – частично имплементиран клас, който дефинира имплементация за някои от методите си, а други оставя абстрактни, без имплементация.
За пример нека разгледаме следния абстрактен клас:
AbstractTest.cs
|
public abstract class Car
{
public void Move()
{
// Move the car
}
abstract public int TopSpeed
{
// Retrieve the top speed in Kmph
get;
}
public abstract string BrandName
{
get;
}
}
|
Дефинирахме клас, който реализира само един от членовете си – метода Move() и дефинира други два, без да ги реализира – свойствата BrandName и TopSpeed.
Абстрактните класове, подобно на интерфейсите, ни помагат по-адекватно да моделираме зависимости от реалният свят, защото чрез тях могат да се представят абстрактни същности. В нашия пример невъзможността за инстанциране на класа Car има смисъл, тъй като и в реалността не можем да имаме кола с неопределена марка.
Абстрактни членове
Ключовата дума abstract в декларацията на класа го определя като абстрактен. Виждаме, че тя може да се приложи и към член. Абстрактни могат да бъдат методите, свойствата, индексаторите и събитията.
Ако в един клас е дефиниран абстрактен член, класът задължително трябва да бъде обявен за абстрактен. В противен случай получаваме грешка при компилация. Обратното не е задължително – допустимо е да имаме абстрактен клас, на който всички членове са дефинирани.
Наследяване на абстрактни класове
Тъй като абстрактните класове са класове, те имат същата структура - същият набор от членове (полета, константи, вложени типове и т. н.), същите модификатори на видимостта и дори същите механизми за наследяване, но с някои особености. Нека разширим предходния пример:
AbstractTest.cs
|
public class Trabant : Car
{
public override int TopSpeed
{
get
{
return 120;
}
}
public override string BrandName
{
get
{
return "Trabant";
}
}
}
public class Porsche : Car
{
public override int TopSpeed
{
get
{
return 250;
}
}
public override string BrandName
{
get
{
return "Porsche";
}
}
}
public class AbstractTest
{
static void Main()
{
Car[] cars = new Car[] {new Trabant(), new Porsche()};
foreach (Car car in cars)
{
Console.WriteLine("A {0} can go {1} Kmph",
car.BrandName, car.TopSpeed);
}
}
}
|
При изпълнението на този код получаваме следния резултат:
A Trabant can go 120 Kmph
A Porsche can go 250 Kmph
|
Виждаме, че въпреки че абстрактният клас не може да се инстанцира директно, обектите от наследяващите го класове могат да се разглеждат като обекти от неговия тип. По показания начин можем да използваме абстрактни базови класове, за да задействаме полиморфизъм, или, казано по-общо, да създадем абстрактен корен на дърво от класове.
В примера ползвахме ключовата дума override, с която указваме, че даден метод в класа наследник припокрива (замества) оригиналния наследен метод от базовия си клас. В случая базовия клас не предоставя имплементация за припокритите методи, така че припокриването е задължително. Ще разгледаме ключовата дума override и нейното действие след малко. Нека сега продължим с абстрактните класове.
Частично реализиране на абстрактните членове
Възможно е абстрактен клас, съдържащ абстрактни членове, да бъде наследен, без всичките му абстрактни членове да бъдат реализирани. Възможно е също клас, който имплементира абстрактните членове на абстрактния си родител, да дефинира допълнително и свои членове, също абстрактни. В този случай класът-наследник също трябва да бъде деклариран като абстрактен, защото съдържа абстрактни членове.
Тези възможности правят още по-гъвкав инструментариума за създаване на йерархии от класове и моделиране на реалния свят. Ще илюстрираме тази възможност със следното разширение на предходния пример:
AbstractTest.cs
|
abstract public class TurboCar : Car
{
protected Boolean mTurboEnabled = false;
public void EnableTurbo()
{
mTurboEnabled = true;
}
public void DisableTurbo()
{
mTurboEnabled = false;
}
}
public class TrabantTurbo : TurboCar
{
override public int TopSpeed
{
get
{
return mTurboEnabled ? 220 : 120;
}
}
override public string BrandName
{
get
{
return "Trabant Turbo";
}
}
}
public class AbstractTest
{
static void Main()
{
TurboCar turboCar = new TrabantTurbo();
Console.WriteLine("A {0} can go {1} Kmph",
turboCar.BrandName, turboCar.TopSpeed);
turboCar.EnableTurbo();
Console.WriteLine(
"A {0} can go {1} Kmph with turbo enabled",
turboCar.BrandName, turboCar.TopSpeed);
}
}
|
Създадохме класа TrabantTurbo, който реализира абстрактните свойства, индиректно наследени от класа TurboCar. Класът TurboCar е разширение на класа Car, който също като него е абстрактен, но предоставя допълнителна функционалност за включване на режим "турбо".
|
Ако един клас наследи от абстрактен и не предостави дефиниции за всички негови абстрактни членове, той трябва задължително също да бъде обявен за абстрактен.
|
След изпълнението на примера получаваме следния резултат:
A Trabant Turbo can go 120 Kmph
A Trabant Turbo can go 220 Kmph with turbo enabled
|
Сподели с приятели: |