1. Giriş
Gəlin abstraksiyaya quş baxışı ilə baxaq: təsəvvür elə böyük bir ofis var, orda müxtəlif işçilər müxtəlif işlər görür. Onların ümumi vəzifəsi ola bilər — "İşçi", hərəsinin də öz xüsusi tapşırığı var. Amma sən, rəhbər kimi, istəyirsən ki, hər bir işçi "İşiYerinəYetir" bacarsın, sənə fərqi yoxdur necə: proqramçı kod yazır, mühasib hesabat çap edir. Bax bu "hamı üçün ümumi kontrakt — detalları isə mütəxəssislər üçün" ideyası düzgün class ierarxiyası qurmağın əsasındadır.
Kodda bu necə görünür?
Hər şey əsas abstrakt class-dan başlayır. O, ən vacib olanı təsvir edir — hamı üçün ortaq olanı.
public abstract class Employee
{
public string Name { get; }
public Employee(string name)
{
Name = name;
}
// Abstrakt metod — bütün işçilər üçün kontrakt
public abstract void DoWork();
}
Sonra törəmə class-lar gəlir — proqramçı və mühasib:
public class Programmer : Employee
{
public Programmer(string name) : base(name) { }
public override void DoWork()
{
Console.WriteLine($"{Name} kod yazır");
}
}
public class Accountant : Employee
{
public Accountant(string name) : base(name) { }
public override void DoWork()
{
Console.WriteLine($"{Name} pul sayır");
}
}
İndi fikir ver: biz işçilərdən ibarət siyahı yarada bilərik — istər mühasib, istər proqramçı, istərsə də başqa biri (abstraksiya belə şeylərə qarşı deyil!).
Employee[] office = new Employee[]
{
new Programmer("Vasya"),
new Accountant("Tanya")
};
foreach (Employee emp in office)
{
emp.DoWork(); // Hər kəs öz işini görür
}
Vasya kod yazır
Tanya pul sayır
Fikir ver, hər şey necə rahat, universal və ən əsası, genişlənə bilən oldu. İstəsən yeni bir class əlavə edə bilərsən, məsələn, Manager, amma artıq olan kodu dəyişməyə ehtiyac yoxdur!
2. Abstraksiyalar əsasında ierarxiyaların qurulması
Demək olar ki, hər OOP dərsliyində heyvanlar nümunəsi var, gəlin biz də ənənəni pozmayaq.
Abstrakt class — "Böyük Diktator" rolunda
public abstract class Animal
{
public string Name { get; set; }
public Animal(string name)
{
Name = name;
}
// Bütün heyvanlar səs çıxarmağı bacarmalıdır
public abstract void MakeSound();
// Amma hamı uça bilmir, ona görə də:
public virtual void Fly()
{
Console.WriteLine("Mən uça bilmirəm.");
}
}
Övlad class-lar: səs çıxarmağı öhdəsinə götürür, başqa metodları da override edə bilər
public class Cat : Animal
{
public Cat(string name) : base(name) { }
public override void MakeSound()
{
Console.WriteLine($"{Name}: Miyau!");
}
}
public class Dog : Animal
{
public Dog(string name) : base(name) { }
public override void MakeSound()
{
Console.WriteLine($"{Name}: Hav!");
}
}
public class Eagle : Animal
{
public Eagle(string name) : base(name) { }
public override void MakeSound()
{
Console.WriteLine($"{Name}: Qışqırıq!");
}
public override void Fly()
{
Console.WriteLine($"{Name} göydə uçur!");
}
}
İndi isə müxtəlif heyvanlardan kolleksiya yığaq:
Animal[] zoo = new Animal[]
{
new Cat("Barsik"),
new Dog("Sharik"),
new Eagle("Orel")
};
foreach (Animal animal in zoo)
{
animal.MakeSound();
animal.Fly();
}
Barsik: Miyau!
Mən uça bilmirəm.
Sharik: Hav!
Mən uça bilmirəm.
Orel: Qışqırıq!
Orel göydə uçur!
Fikir ver, artıq istənilən törəmə class-lardan istifadə etmək çox asandır: kolleksiyada hansı obyektin olduğunu düşünmürük. Abstraksiya "kontrakt"a cavabdehdir, detalları isə konkret davranış həll edir.
3. Bir neçə səviyyədə abstraksiya
Abstraksiya təkcə əsas class və onun birbaşa törəmələri ilə məhdudlaşmır. Çətin sistemlərdə tez-tez bir neçə səviyyədə olur, yəni bir abstrakt class digərinin üzərində qurulur. Bu, lay-lay torta (və ya Şrekin dediyi kimi, soğana) bənzəyir: hər qat artıq detalları gizlədir, yalnız lazım olanı saxlayır.
Nümunə: Nəqliyyat vasitələrinin ierarxiyası
. Vehicle (abstract)
/ | \
Car Airplane Boat
ElectricCar JetAirplane SailBoat
Burada Vehicle ümumi prinsipləri müəyyən edir (məsələn, Move() metodu), amma maşının və ya təyyarənin necə hərəkət edəcəyini bilmir. Bunu törəmə class-lar müəyyən edir. Daha konkret class-lar, məsələn, ElectricCar və ya JetAirplane, öz detallarını əlavə edib funksionallığı genişləndirə bilər.
Blok-sxem ierarxiyası:
. +------------------+
| Vehicle | <--- abstrakt class
+------------------+
/ \
+-------+ +-------+
| Car | | Boat | <--- aralıq abstraksiyalar və ya konkret class-lar
+-------+ +-------+
Kod: əsas abstrakt class
public abstract class Vehicle
{
public string Model { get; }
public Vehicle(string model)
{
Model = model;
}
// Abstrakt metod
public abstract void Move();
}
Aralıq abstrakt class
Bəzən aralıq səviyyədə də abstraksiyalara ehtiyac olur!
public abstract class Car : Vehicle
{
public Car(string model) : base(model) { }
public override void Move()
{
Console.WriteLine($"{Model} yolda gedir.");
}
// Abstrakt metod — hər maşın elektrikli deyil:
public abstract void RefuelOrCharge();
}
Konkret reallaşdırmalar
public class ElectricCar : Car
{
public ElectricCar(string model) : base(model) { }
public override void RefuelOrCharge()
{
Console.WriteLine($"{Model} elektriklə doldurulur.");
}
}
public class GasolineCar : Car
{
public GasolineCar(string model) : base(model) { }
public override void RefuelOrCharge()
{
Console.WriteLine($"{Model} benzinlə doldurulur.");
}
}
Nəticə: bir neçə səviyyədə abstraksiya yeni class-lar və funksiyalar əlavə etməyi asanlaşdırır.
Vizualizasiya: class ierarxiyası nümunəsi
| Class | Tip | Abstrakt | Valideyn | Xüsusi davranış |
|---|---|---|---|---|
| Vehicle | Əsas | Bəli | - | Abstrakt metod Move() |
| Car | Aralıq | Bəli | Vehicle | Abstrakt RefuelOrCharge() |
| ElectricCar | Son | Xeyr | Car | RefuelOrCharge() reallaşdırması |
| GasolineCar | Son | Xeyr | Car | RefuelOrCharge() reallaşdırması |
| Boat | Son | Xeyr | Vehicle | Move() reallaşdırması |
4. Abstraksiyanın genişlənə bilən tətbiqlərdə istifadəsi
Praktik fayda:
- Kodun çevikliyi və genişlənməsi: Yeni bir class əlavə edə bilərsən (məsələn, yeni heyvan, nəqliyyat vasitəsi və ya işçi tipi), artıq yazılmış işlək kodu dəyişmədən. Sənin dövrün/metodların yeni obyektlə avtomatik işləyəcək — əsas odur ki, abstraksiyada müəyyən olunan metodları reallaşdırsın.
- Kodun təkrarlanmasının minimuma endirilməsi: Ümumi xüsusiyyətlər və metodlar (məsələn, ad, əsas məntiq) bir dəfə abstrakt class-da müəyyən olunur, törəmələr isə avtomatik əldə edir.
- Böyük framework və sistemlərdə geniş yayılmış yanaşma: Məsələn, ASP.NET MVC-də abstrakt əsas controller-lər (ControllerBase), WinForms-da isə bütün UI elementləri üçün abstrakt Control class-ı var. Bu, framework-u genişləndirməyə imkan verir, artıq yazılmış hissələrin sabitliyini pozmadan.
Harada lazım olacaq?
- İstənilən böyük sistemlərdə: bank tətbiqləri (işçilər, əməliyyatlar və tranzaksiyalar), oyunlar (oyun obyektləri, personajlar), biznes tətbiqləri (kataloqlar, məhsullar, istifadəçilər), istənilən ierarxik və strukturlu məlumatlar.
- Texniki müsahibələrdə: Abstraksiyalar əsasında class-lar qurmaq və ierarxiyanı izah etmək bacarığı — tez-tez müsahibə sualıdır.
- Proqram arxitekturası: Abstraksiya "skelet" arxitekturanı məntiq yazılmamışdan əvvəl qurmağa imkan verir — komanda ilə işləmək, TDD (testlərlə inkişaf) və ümumiyyətlə dəstəklənə bilən kod üçün rahatdır.
5. İerarxiya qurarkən tipik səhvlər və tələlər
Səhv №1: abstrakt metodun reallaşdırılması unudulub.
Kompilyator əsas class-dakı bütün abstrakt üzvlər reallaşdırılmayıbsa, törəmə class-dan obyekt yaratmağa imkan verməyəcək. Bu məcburi qaydadır — yazılmamış qanun kimidir: konkret olmaq istəyirsənsə — hər şeyi reallaşdır.
Səhv №2: bir neçə abstrakt class-dan birdən irsi almağa cəhd.
C#-da eyni anda bir neçə class-dan irsi almaq olmaz, hətta hamısı abstrakt olsa belə. Bu, dilin məhdudiyyətidir. Əgər müxtəlif mənbələrdən davranış "irsi almaq" lazımdırsa — interface-lərdən istifadə et. Onlar abstrakt class kimidir, amma daha yüngül və reallaşdırmasızdır.
Səhv №3: aralıq abstrakt class-ların mənasını başa düşməmək.
Belə class-lar tez-tez ümumi məntiqi qruplaşdırmaq və "yarımçıq" obyektlərin yaradılmasından qorumaq üçün istifadə olunur. Məsələn, Car class-ı abstrakt ola bilər ki, heç kim sadəcə "maşın" yaratmasın, hansı növ olduğunu dəqiqləşdirmədən: benzinli, dizelli, yoxsa elektrikli.
GO TO FULL VERSION