JavaRush /Java Blogu /Random-AZ /Java-da çoxlu miras. Tərkib və irsiyyətin müqayisəsi
HonyaSaar
Səviyyə
Москва

Java-da çoxlu miras. Tərkib və irsiyyətin müqayisəsi

Qrupda dərc edilmişdir
Bir müddət əvvəl Java-da miras, interfeyslər və kompozisiya haqqında bir neçə yazı yazdım. Bu yazıda biz çoxlu varisliyə baxacağıq və sonra kompozisiyanın miras üzərində üstünlükləri haqqında öyrənəcəyik.
Java-da çoxlu miras.  Tərkib və irsiyyətin müqayisəsi - 1

Java-da çoxlu varislik

Çoxlu miras çoxlu valideyn sinifləri ilə siniflər yaratmaq qabiliyyətidir. C++ kimi digər məşhur obyekt yönümlü dillərdən fərqli olaraq, Java çox sinif irsini dəstəkləmir. O, "almaz problemi" ilə qarşılaşma ehtimalına görə bunu dəstəkləmir və əvəzində oxşar miras nəticəsinə nail ola biləcəyimiz ən yaxşı variantlardan istifadə edərək, onu həll etmək üçün bir növ kompleks yanaşma təqdim etməyə üstünlük verir.

"Almaz problemi"

Almaz problemini daha sadə başa düşmək üçün tutaq ki, Java-da çoxlu varislik dəstəklənir. Bu halda biz aşağıdakı şəkildə göstərilən iyerarxiya ilə siniflər əldə edə bilərik. almaz sinfi iyerarxiyasıFərz edək ki, bu, SuperClassmüəyyən bir metodu təsvir edən mücərrəd bir sinifdir və siniflər ClassAClassBreal siniflərdir. SuperClass.java
package com.journaldev.inheritance;
public abstract class SuperClass {
   	public abstract void doSomething();
}
ClassA.java
package com.journaldev.inheritance;
public class ClassA extends SuperClass{
    @Override
 public void doSomething(){
        System.out.println("Какая-то реализация класса A");
    }
  //собственный метод класса  ClassA
    public void methodA(){
    }
}
İndi fərz edək ki, sinif eyni zamanda ondan ClassCmiras alır və eyni zamanda aşağıdakı icraya malikdir: ClassA ClassB
package com.journaldev.inheritance;
public class ClassC extends ClassA, ClassB{
    public void test(){
        //вызов метода родительского класса
        doSomething();
    }
}
Qeyd edək ki, metod ana sinifin test()metodunu çağırır doSomething()və bu, qeyri-müəyyənliyə gətirib çıxaracaq, çünki kompilyator hansı superklass metodunun çağırılmalı olduğunu bilmir. Fasetli almazın konturuna bənzəyən bu vəziyyətdə sinif irsiyyət diaqramının formasına görə problem “Almaz problemi” adlanır. Java-nın çoxlu sinif irsini dəstəkləməməsinin əsas səbəbi budur. Qeyd edək ki, çoxsaylı sinif irsiyyəti ilə bağlı bu problem ən azı bir ümumi metodu olan üç sinifdə də baş verə bilər.

Çoxsaylı miras və interfeyslər

Ola bilsin ki, mən həmişə “siniflər arasında çoxlu varislik dəstəklənmir” dediyimi, lakin interfeyslər arasında dəstəkləndiyini görmüsünüz. Sadə bir nümunə aşağıda göstərilmişdir: InterfaceA.java
package com.journaldev.inheritance;
public interface InterfaceA {

    public void doSomething();
}
InterfaceB.java
package com.journaldev.inheritance;

public interface InterfaceB {

    public void doSomething();
}
Diqqət yetirin ki, hər iki interfeysdə eyni adlı metod var. İndi deyək ki, hər iki interfeysdən miras qalan bir interfeysimiz var. InterfaceC.java
package com.journaldev.inheritance;

public interface InterfaceC extends InterfaceA, InterfaceB {

    //метод, с тем же названием описан в  InterfaceA и InterfaceB
    public void doSomething();
Burada hər şey idealdır, çünki interfeyslər yalnız metodun rezervasiyası/təsviridir və metodun özü bu interfeysləri həyata keçirən konkret sinifdə olacaq, ona görə də interfeyslərin çoxsaylı varisliyi ilə qeyri-müəyyənliklə qarşılaşmaq imkanı yoxdur. Buna görə Java-da siniflər bir çox interfeysdən miras qala bilər. Bunu aşağıdakı nümunə ilə göstərək. InterfacesImpl.java
package com.journaldev.inheritance;

public class InterfacesImpl implements InterfaceA, InterfaceB, InterfaceC {

    @Override
    public void doSomething() {
        System.out.println("doSomething реализация реального класса ");
    }

    public static void main(String[] args) {
        InterfaceA objA = new InterfacesImpl();
        InterfaceB objB = new InterfacesImpl();
        InterfaceC objC = new InterfacesImpl();

        //все вызываемые ниже методы получат одинаковую реализацию конкретного класса

        objA.doSomething();
        objB.doSomething();
        objC.doSomething();
    }
}
Ola bilsin ki, siz hər dəfə supersinifdə və ya interfeysdə təsvir edilən metodu ləğv edəndə @Override annotasiyasından istifadə etdiyimi görmüsünüz. Bu, üç daxili Java annotasiyasından biridir və siz üsulları ləğv edərkən həmişə ondan istifadə etməlisiniz.

Qurtuluş kimi kompozisiya

methodA()Beləliklə, biz sinif ClassAmethodB()sinif ClassBfunksiyasından istifadə etmək istəsək nə olacaq ClassС? Bunun həlli kompozisiya ola bilər - ClassChəm sinif metodlarını tətbiq edən ClassA, həm də obyektlərdən biri üçün ClassBtətbiqi olan yenidən yazılmış versiya. doSomething() ClassC.java
package com.journaldev.inheritance;

public class ClassC{

    ClassA objA = new ClassA();
    ClassB objB = new ClassB();

    public void test(){
        objA.doSomething();
    }

    public void methodA(){
        objA.methodA();
    }

    public void methodB(){
        objB.methodB();
    }
}

Tərkib, yoxsa miras?

Varislik üzərində kompozisiyadan istifadə etmək yaxşı Java proqramlaşdırma təcrübəsidir. Bu yanaşmanın lehinə bəzi aspektlərə baxacağıq.
  1. Tutaq ki, valideyn-varis siniflərinin aşağıdakı birləşməsinə sahibik:

    ClassC.java

    package com.journaldev.inheritance;
    
    public class ClassC{
    
    public void methodC(){
      	}
    
    }

    ClassD.java

    package com.journaldev.inheritance;
    
    public class ClassD extends ClassC{
    
        public int test(){
            return 0;
        }
    }

    Yuxarıdakı kod tərtib edir və yaxşı işləyir, lakin ClassCfərqli şəkildə həyata keçirilsə nə olacaq:

    package com.journaldev.inheritance;
    
    public class ClassC{
    
        public void methodC(){
        }
    
        public void test(){
        }
    }

    Nəzərə alın ki, metod test()artıq nəsil sinifində mövcuddur, lakin fərqli bir növün nəticəsini qaytarır. İndi ClassDbir IDE istifadə edirsinizsə, o, tərtib etməyəcək. Sizə nəsil və ya super sinifdə qaytarma növünü dəyişdirməyiniz tövsiyə olunacaq.

    İndi siniflərin çoxsəviyyəli irsiyyətinin olduğu və dəyişikliklərimiz üçün superklassın mövcud olmadığı bir vəziyyəti təsəvvür edək. İndi kompilyasiya xətasından xilas olmaq üçün alt sinif metodunun imzasını və ya adını dəyişməkdən başqa seçimimiz yoxdur. Bu metodun çağırıldığı bütün yerlərdə də dəyişiklik etməli olacağıq. Beləliklə, miras kodumuzu kövrək edir.

    Yuxarıda təsvir edilən problem kompozisiya vəziyyətində heç vaxt baş vermir və buna görə də ikincini mirasdan üstün edir.

  2. Vərəsəliklə bağlı növbəti problem odur ki, biz valideynin bütün üsullarını müştəriyə təqdim edirik. Və əgər super sinif çox düzgün tərtib olunmayıbsa və təhlükəsizlik dəlikləri varsa. Sonra, alt sinifimizin həyata keçirilməsində təhlükəsizliyin tam qayğısına qalsaq da, yenə də ana sinifin qüsurlu tətbiqindən asılı olacağıq.

    Kompozisiya bizə supersinifin metodlarına nəzarət edilən girişi təmin etməkdə kömək edir, halbuki miras onun metodları üzərində heç bir nəzarəti saxlamır. Bu həm də kompozisiyanın varislik üzərində əsas üstünlüklərindən biridir.

  3. Kompozisiyanın başqa bir üstünlüyü ondan ibarətdir ki, metodları çağırarkən çeviklik əlavə edir. Yuxarıda təsvir edilən sinfin həyata keçirilməsi ClassCoptimal deyil və çağırılan metoda erkən bağlanmadan istifadə edir. Minimal dəyişikliklər bizə metod çağırışını çevik etməyə və gec bağlanmağa imkan verəcək (iş zamanı bağlama).

    ClassC.java

    package com.journaldev.inheritance;
    public class ClassC{
        SuperClass obj = null;
        public ClassC(SuperClass o){
            this.obj = o;
        }
        public void test(){
            obj.doSomething();
        }
    
        public static void main(String args[]){
            ClassC obj1 = new ClassC(new ClassA());
            ClassC obj2 = new ClassC(new ClassB());
    
            obj1.test();
            obj2.test();
        }
    }

    Yuxarıdakı proqram göstərəcək:

    doSomething implementation of A
    doSomething implementation of B

    Metod çağırışında bu çeviklik mirasla görünmür, bu da kompozisiyanı ən yaxşı yanaşma edir.

  4. Kompozisiya vəziyyətində vahid sınağı daha asandır, çünki bilirik ki, super sinifdə istifadə olunan bütün üsullar üçün testləri kəsə bilərik, irsiyyətdə isə biz superklassdan çox asılıdır və ana sinfin metodlarının necə işlədiyini bilmirik. istifadə olunacaq. Deməli, irsiyyətə görə biz superklassın bütün üsullarını sınaqdan keçirməli olacağıq ki, bu da lazımsız işdir.

    İdeal olaraq, miras yalnız “ is-a ” əlaqəsi valideyn və uşaq sinifləri üçün doğru olduqda istifadə edilməlidir , əks halda kompozisiyaya üstünlük verilməlidir.

Orijinal məqalə
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION