JavaRush /Java Blogu /Random-AZ /Java-da çoxlu miras. Tərkibi vərəsəlik
DSergey_Kh
Səviyyə

Java-da çoxlu miras. Tərkibi vərəsəlik

Qrupda dərc edilmişdir

Java-da çoxlu varislik

Çoxlu miras çoxlu supersiniflərdən miras qalan sinif yaratmağa imkan verir. C++ kimi bəzi digər məşhur obyekt yönümlü proqramlaşdırma dillərindən fərqli olaraq, Java siniflərdən çoxlu miras almağa imkan vermir. Java çox sinif irsiyyətini dəstəkləmir, çünki bu, almaz probleminə səbəb ola bilər. Və bu problemi həll etməyin yollarını axtarmaq əvəzinə, çoxlu miras kimi eyni nəticəni əldə edə biləcəyimiz daha yaxşı variantlar var.

Almaz problemi

Almaz problemini daha asan başa düşmək üçün tutaq ki, Java-da çoxlu varislik dəstəklənir. Bu halda, aşağıdakı şəkildə göstərildiyi kimi bir sinif iyerarxiyasına sahib ola bilərik. Java-da çoxlu miras.  Tərkibi vərəsəlik - 1Fərz edək ki, sinif SuperClassmücərrəddir və orada hansısa metod elan olunub. Həm konkret siniflər, ClassAhəm də ClassB.
package com.journaldev.inheritance;
public abstract class SuperClass {
	public abstract void doSomething();
}
package com.journaldev.inheritance;
public class ClassA extends SuperClass{
	@Override
	public void doSomething(){
		System.out.println("doSomething implementation of A");
	}
	//ClassA own method
	public void methodA(){
	}
}
package com.journaldev.inheritance;
public class ClassB extends SuperClass{
	@Override
	public void doSomething(){
		System.out.println("doSomething implementation of B");
	}
	//ClassB specific method
	public void methodB(){
	}
}
ClassCİndi fərz edək ki, biz həyata keçirmək və onu ClassAvə -dən miras almaq istəyirik ClassB.
package com.journaldev.inheritance;
public class ClassC extends ClassA, ClassB{
	public void test(){
		//calling super class method
		doSomething();
	}
}
Qeyd edək ki, metod test()superclass metodunu çağırır doSomething(). Bu, qeyri-müəyyənliyə gətirib çıxarır, çünki kompilyator hansı superclass metodunu icra edəcəyini bilmir. Bu almaz problemi adlanan almaz formalı sinif diaqramıdır. Java-nın çoxlu varisliyi dəstəkləməməsinin əsas səbəbi budur. Qeyd edək ki, yuxarıda göstərilən çoxsaylı sinif irsi problemi yalnız ən azı bir ümumi metodu olan üç sinifdə baş verə bilər.

Çoxsaylı İnterfeys Varisliyi

Java-da siniflərdə çoxlu varislik dəstəklənmir, lakin interfeyslərdə dəstəklənir. Və bir interfeys bir çox digər interfeysləri genişləndirə bilər. Aşağıda sadə bir nümunə var.
package com.journaldev.inheritance;
public interface InterfaceA {
	public void doSomething();
}
package com.journaldev.inheritance;
public interface InterfaceB {
	public void doSomething();
}
Qeyd edək ki, hər iki interfeys eyni metodu elan edir. İndi biz aşağıdakı nümunədə göstərildiyi kimi bu interfeyslərin hər ikisini genişləndirən interfeys yarada bilərik.
package com.journaldev.inheritance;
public interface InterfaceC extends InterfaceA, InterfaceB {
	//same method is declared in InterfaceA and InterfaceB both
	public void doSomething();
}
Bu əla işləyir, çünki interfeyslər yalnız metodları elan edir və tətbiq interfeysi miras alan siniflərdə həyata keçiriləcək. Beləliklə, çoxlu interfeys varisliyində qeyri-müəyyənlik əldə etmək üçün heç bir yol yoxdur.
package com.journaldev.inheritance;
public class InterfacesImpl implements InterfaceA, InterfaceB, InterfaceC {
	@Override
	public void doSomething() {
		System.out.println("doSomething implementation of concrete class");
	}
	public static void main(String[] args) {
		InterfaceA objA = new InterfacesImpl();
		InterfaceB objB = new InterfacesImpl();
		InterfaceC objC = new InterfacesImpl();

		//all the method calls below are going to same concrete implementation
		objA.doSomething();
		objB.doSomething();
		objC.doSomething();
	}
}
Nəzərə alın ki, hər hansı superclass metodunu ləğv etdikdə və ya interfeys metodunu həyata keçirdiyiniz zaman annotasiyadan istifadə edin @Override. methodA()Bir sinif funksiyasından ClassAmethodB()bir sinif funksiyasından ClassBbir sinifdə istifadə etmək istəsək nə olacaq ClassC? Həll kompozisiyanın istifadəsindədir. ClassCAşağıda həm sinif metodlarını, həm də doSomething()obyektlərdən birinin metodunu müəyyən etmək üçün kompozisiyadan istifadə edən sinfin versiyası var .
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ərkibi vərəsəlik

Ən yaxşı Java proqramlaşdırma təcrübələrindən biri “mirasdan əvvəl tərkibi təsdiqləməkdir”. Bu yanaşmaya üstünlük verən bəzi aspektləri araşdıracağıq.
  1. Deyək ki, bizim super sinifimiz və onu genişləndirən bir sinifimiz var:

    package com.journaldev.inheritance;
    public class ClassC{
    	public void methodC(){
    	}
    }
    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. Ancaq sinifin tətbiqini ClassCaşağıda göstərildiyi kimi dəyişdirsək nə olar:

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

    Qeyd edək ki, metod test()artıq alt sinifdə mövcuddur, lakin qaytarma növü fərqlidir. İndi sinif ClassDkompilyasiya etməyəcək və əgər siz hər hansı bir IDE istifadə etsəniz, o, sizə supersinif və ya alt sinifdə qaytarma növünü dəyişməyi təklif edəcək.

    İndi elə bir vəziyyəti təsəvvür edin ki, bizdə çoxsəviyyəli sinif irsiyyət iyerarxiyası var və superklassa çıxışımız yoxdur. Kompilyasiya xətasını aradan qaldırmaq üçün alt sinif metodu imzamızı və ya onun adını dəyişməkdən başqa seçimimiz olmayacaq. Həm də alt sinif metodunu çağırıldığı bütün yerlərdə dəyişdirməli olacağıq. Beləliklə, miras kodumuzu kövrək edir.

    Yuxarıdakı problem kompozisiya ilə heç vaxt baş verməyəcək və bu onu miras üçün daha cəlbedici edir.

  2. Vərəsəliklə bağlı başqa bir problem odur ki, biz superklassın bütün üsullarını müştəriyə təqdim edirik və əgər super sinifimiz düzgün tərtib olunmayıbsa və təhlükəsizlik boşluqları varsa, sinfimizin ən yaxşı tətbiqini həyata keçirsək də, zəif tətbiqdən təsirlənirik. super sinifdən. Kompozisiya bizə superclass metodlarına nəzarət edilən girişi təmin etməkdə kömək edir, halbuki miras superklass metodları üzərində nəzarəti təmin etmir. Bu, həm də irsiyyətdən kompozisiyanın əsas üstünlüklərindən biridir.

  3. Kompozisiyanın başqa bir üstünlüyü ondan ibarətdir ki, o, çağırış üsullarında çevikliyə imkan verir. Yuxarıda təqdim etdiyimiz sinifin tətbiqi ClassCoptimal deyil və tərtib vaxtının çağırılacaq metoda bağlı olmasını təmin edir. Minimum dəyişikliklərlə metod çağırışını çevik və dinamik edə bilərik.

    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ıda göstərilən proqramın nəticəsi:

    doSomething implementation of A
    doSomething implementation of B

    Metod çağırışında bu çeviklik mirasla mövcud deyil, bu da kompozisiya seçiminə başqa bir üstünlük verir.

  4. Bölmə testini kompozisiya ilə etmək daha asandır, çünki biz bilirik ki, biz super sinifdəki bütün üsullardan istifadə edirik və onları sınaq üçün kopyalaya bilərik. Halbuki mirasda biz daha çox supersinfdən asılıyıq və istifadə olunacaq supersinifin bütün üsullarını bilmirik. Beləliklə, biz irsiyyət səbəbindən əlavə iş olan superklassın bütün üsullarını sınaqdan keçirməliyik.

    İdeal olaraq, biz mirasdan yalnız alt sinifdən supersinif əlaqəsi "olur" kimi müəyyən edildikdə istifadə etməliyik. Bütün digər hallarda kompozisiyadan istifadə etmək tövsiyə olunur.

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