CodeGym /Kurslar /JAVA 25 SELF /Polimorfizm anlayışı və nə üçün lazımdır

Polimorfizm anlayışı və nə üçün lazımdır

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. Giriş

Polimorfizm — obyekt yönümlü proqramlaşdırmanın (irsiyyət və enkapsulyasiya ilə yanaşı) üç əsas konsepsiyasından biridir. Söz etimoloji olaraq yunan dilində «poly» (çox) və «morph» (forma) sözlərindən gəlir. Proqramlaşdırmada bu belə deməkdir: bir interfeys — çox implementasiya.

Tərif

Polimorfizm — müxtəlif siniflərin obyektlərinin eyni mesajlara (metod çağırışlarına) fərqli reaksiya vermək qabiliyyətidir.

Yəni, əgər sizdə makeSound() metodu varsa, onu istənilən heyvan üçün çağıra bilərsiniz, amma pişik «miyau» edəcək, it «haflayacaq», inək isə «möö» edəcək. Proqramçı üçün bu sadəcə animal.makeSound() çağırışıdır, lakin əslində nə baş verəcəyi — həmin dəyişənin arxasında hansı obyektin durmasından asılıdır.

Həyatdan analogiya

Təsəvvür edin, evdə televizorun pultu var və elə həmin pultla səsucaldanları, proyektoru, hətta qəhvə aparatını idarə edə bilərsiniz. Siz «Yandır» — turnOn() düyməsinə basırsınız və hər cihaz özünəməxsus reaksiya verir. Əsas olan — hamısında «yandırma» düyməsi var, amma implementasiya fərqlidir.

Java üzrə nümunə

class Animal {
    void makeSound() {
        System.out.println("Hər hansı bir səs...");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Haf!");
    }
}

class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Miyau!");
    }
}

class Cow extends Animal {
    @Override
    void makeSound() {
        System.out.println("Mööö!");
    }
}

İndi bunu belə edə bilərik:

Animal animal1 = new Dog();
Animal animal2 = new Cat();
Animal animal3 = new Cow();

animal1.makeSound(); // Haf!
animal2.makeSound(); // Miyau!
animal3.makeSound(); // Mööö!

Nəzərə alın: bütün dəyişənlərin tipi Animal-dır, amma çağırışın nəticəsi obyektin faktiki tipindən asılıdır.

2. Polimorfizmin növləri

Java-da (və əksər OOP dillərində) polimorfizmin iki əsas növü fərqləndirilir:

Kompilyator (statik) polimorfizm — metodların aşırı yüklənməsi (overloading)

Bu, eyni sinifdə adı eyni, parametrləri fərqli olan bir neçə metod olduqda baş verir. Kompilyator verilən arqumentlərə əsasən hansı metodun çağırılacağını özü müəyyən edir.

Nümunə (bir az qabağa baxaq — ətraflı izah növbəti mühazirədə olacaq):

class Printer {
    void print(int x) {
        System.out.println("Ədəd: " + x);
    }

    void print(String s) {
        System.out.println("Sətir: " + s);
    }
}

İcra zamanı (dinamik) polimorfizm — metodların yenidən təyin edilməsi (overriding)

Bu zaman metod baza sinifdə müəyyən edilir, sonra isə törəmə siniflərdə yenidən təyin olunur. Hansı metodun çağırılacağı — proqramın icrası zamanı obyektin faktiki tipindən asılı olaraq müəyyən edilir.

Nümunə — yuxarıdakı heyvanlar nümunəsinə baxın.

3. Polimorfizm nə üçün lazımdır?

Polimorfizm — təkcə müsahibələr üçün gözəl bir söz deyil. Bu, kodunuzu çevik, genişlənə bilən və dəstəklənməsi asan edən bir alətdir.

Kodun universallığı

İcra detallarını düşünmədən baza tipli obyektlərlə işləyən kod yaza bilərsiniz. Məsələn, əgər sizdə heyvanların siyahısı varsa, onun üzərindən keçib hər biri üçün makeSound() çağıra bilərsiniz — pişiktir, itdir, bunu düşünməyinizə ehtiyac yoxdur.

Animal[] animals = { new Dog(), new Cat(), new Cow() };

for (Animal animal : animals) {
    animal.makeSound(); // Hər dəfə "doğru" metod çağırılacaq
}

Asan genişləndirmə

Əgər sabah rəisinız desə: «Gəlin tutuquşu əlavə edək!», sadəcə yeni Parrot extends Animal sinfini yazıb onu massivə əlavə edirsiniz. Qalan bütün kod dəyişməz qalır. Bu — genişləndirməyə açıq, dəyişikliklərə qapalı olmaq deməkdir (SOLID-in OCP prinsipi).

Arxitekturanın sadələşdirilməsi

Müxtəlif hissələrin konkret implementasiyaları düşünmədən abstraksiyalar (baza siniflər və ya interfeyslər) vasitəsilə qarşılıqlı əlaqədə olduğu mürəkkəb sistemlər qura bilərsiniz. Bu, vaxtı, əsəbləri və qəhvəni qənaət edir.

4. Açar anlayışlar: istinad tipi və faktiki tip

Dəyişənin istinad tipi
Animal animal = new Dog(); yazdığınız zaman animal dəyişəninin istinad tipi Animal olur, yəni kompilyator «düşünür» ki, bu bir heyvandır və yalnız Animal sinfində elan olunmuş metodlara icazə verir.

Obyektin faktiki (real) tipi
Amma yaddaşda əslində Dog tipli obyekt yerləşir. Məhz o, makeSound() çağırıldıqda hansı metodun işə düşəcəyini müəyyən edir.

İllustrasiya

Animal animal = new Dog();
animal.makeSound(); // Dog.makeSound() çağırılacaq, Animal.makeSound() yox

Vacibdir! Baza tipli istinad (Animal) vasitəsilə yalnız Dog-da olan, amma baza sinifdə elan olunmamış metodları çağıra bilməyəcəksiniz.

Gec (dinamik) bağlama
Bu, icra zamanı baş verən «sehr»dir: metodu baza tipli istinad vasitəsilə çağırdığınızda JVM obyektin faktiki tipinə baxır və «doğru» implementasiyanı çağırır. Bu, polimorfizmin iş başında olmağıdır.

5. Praktik nümunə: tətbiqdə polimorfizm

Gəlin tədris tətbiqimizi inkişaf etdirməyə davam edək. Tutaq ki, sadə bir zoopark simulyasiyası yazırıq. Bizdə Animal adlı baza sinif və onun bir neçə törəməsi var. Bütün heyvanların «səs çıxarmasını» istəyirik, amma hər heyvan tipi üçün ayrıca kod yazmaq istəmirik.

Addım 1: Baza sinif və törəmələr

class Animal {
    void makeSound() {
        System.out.println("Hər hansı bir səs...");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Haf!");
    }
}

class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Miyau!");
    }
}

Addım 2: Heyvanlar massivi

Animal[] zoo = { new Dog(), new Cat(), new Animal() };

Addım 3: Dövr və metod çağırışı

for (Animal animal : zoo) {
    animal.makeSound();
}

İcra nəticəsi:

Haf!
Miyau!
Hər hansı bir səs...

Nəzərə alın: massivdə əvvəlcədən kimin olduğunu bilmirik — proqram özü düzgün metodu çağırır.

6. Polimorfizmin sxematik təsviri


.        Animal (makeSound)
           /        \
        Dog        Cat
     (makeSound) (makeSound)

Animal animal = new Dog();
animal.makeSound(); // --> Dog.makeSound()

Animal animal = new Cat();
animal.makeSound(); // --> Cat.makeSound()

7. Başqa bir nümunə: real vəzifədə polimorfizm

Tutaq ki, siz şirkət əməkdaşlarının idarə olunması üçün proqram yazırsınız. Sizdə Employee adlı baza sinif və iki törəmə var: ManagerDeveloper. Bütün əməkdaşlar işləyə bilər — work(), amma bunu müxtəlif cür edirlər.

class Employee {
    void work() {
        System.out.println("İşçi işləyir.");
    }
}

class Manager extends Employee {
    @Override
    void work() {
        System.out.println("Menecer iclas keçirir.");
    }
}

class Developer extends Employee {
    @Override
    void work() {
        System.out.println("Tərtibatçı kod yazır.");
    }
}

İndi bunu belə edə bilərsiniz:

Employee[] staff = { new Manager(), new Developer(), new Employee() };

for (Employee emp : staff) {
    emp.work();
}

Nəticə:

Menecer iclas keçirir.
Tərtibatçı kod yazır.
İşçi işləyir.

8. Polimorfizm nə zaman işləmir

Polimorfizm yalnız baza sinifdə elan edilmiş metodlar üçün işləyir. Əgər törəmə sinifdə unikal metod varsa, onu baza tipli istinad vasitəsilə görməyəcəksiniz.

class Dog extends Animal {
    void fetchStick() {
        System.out.println("İt çubuğu gətirir!");
    }
}

Animal animal = new Dog();
// animal.fetchStick(); // Kompilyasiya xətası! Belə bir metod Animal vasitəsilə görünmür

Xüsusi metodu çağırmaq üçün dəyişəni lazım olan tipə çevirmək lazımdır:

if (animal instanceof Dog) {
    ((Dog) animal).fetchStick();
}

Amma bu artıq başqa bir hekayədir — əsas fikir: polimorfizm vasitəsilə yalnız baza sinifdə elan olunan metodlara çıxış var.

9. Polimorfizmlə işləyərkən tipik səhvlər

Səhv № 1: Baza tipli istinad vasitəsilə törəmə sinfin bütün metodlarının əlçatan olacağını gözləmək. Əslində, yalnız baza sinifdə elan olunan metodlar əlçatandır.

Səhv № 2: Metodu yenidən təyin edərkən @Override annotasiyasından istifadə etməmək. Onsuz səhv imza ilə metod yaza bilərsiniz və bu halda polimorfizm işləməyəcək (baza sinfinin metodu yenidən təyin olunmayacaq).

Səhv № 3: Törəmə sinfə məxsus xüsusi metodu tip çevirməsi etmədən çağırmağa cəhd. Kompilyator buna icazə verməyəcək, çünki istinadı göstərən obyektin kim olduğunu bilmir.

Səhv № 4: overloading (aşırı yüklənmə) ilə overriding (yenidən təyin etmə) arasında qarışıqlıq. Overloading — eyni sinifdə adı eyni, parametrləri fərqli bir neçə metodun olmasıdır. Overriding — metodun davranışını törəmə sinifdə dəyişdirməkdir.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Heyvanlar aləmində macəralar: Polimorfizm dərsi!
Heyvanlar aləmində macəralar: Polimorfizm dərsi!
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Ferma xoru: Bir neçə səsli polimorfizm
Ferma xoru: Bir neçə səsli polimorfizm
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Korporativ labirint: Polimorfizm və işçinin rolu
Korporativ labirint: Polimorfizm və işçinin rolu
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Avtoparkın genişləndirilməsi: Polimorfizm və yeni nəqliyyat növləri
Avtoparkın genişləndirilməsi: Polimorfizm və yeni nəqliyyat növləri
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION