JavaRush /Java blogi /Random-UZ /Java-da bir nechta meros. Tarkibi va merosni taqqoslash
HonyaSaar
Daraja
Москва

Java-da bir nechta meros. Tarkibi va merosni taqqoslash

Guruhda nashr etilgan
Bir muncha vaqt oldin men Java-da meros, interfeys va kompozitsiya haqida bir nechta postlar yozganman. Ushbu maqolada biz bir nechta merosni ko'rib chiqamiz va keyin kompozitsiyaning merosga nisbatan afzalliklari haqida bilib olamiz.
Java-da bir nechta meros.  Tarkibi va merosni taqqoslash - 1

Java-da bir nechta meros

Bir nechta meros - bu bir nechta ota-sinflar bilan sinflar yaratish qobiliyati. C++ kabi boshqa mashhur ob'ektga yo'naltirilgan tillardan farqli o'laroq, Java bir nechta sinf merosini qo'llab-quvvatlamaydi. U "olmos muammosi" ga duch kelish ehtimoli tufayli uni qo'llab-quvvatlamaydi va o'rniga biz shunga o'xshash meros natijasiga erishishimiz mumkin bo'lgan eng yaxshi variantlardan foydalanib, uni hal qilish uchun qandaydir kompleks yondashuvni taqdim etishni afzal ko'radi.

"Olmos muammosi"

Olmos muammosini soddaroq tushunish uchun, keling, Java-da bir nechta meros qo'llab-quvvatlanadi deb faraz qilaylik. Bunday holda, biz quyidagi rasmda ko'rsatilgan ierarxiya bilan sinflarni olishimiz mumkin. olmos sinfi ierarxiyasiFaraz qilaylik, SuperClassbu ma'lum bir usulni tavsiflovchi mavhum sinf, va sinflar ClassAva ClassBhaqiqiy sinflar. 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(){
    }
}
Keling, sinf bir vaqtning o'zida ClassCmerosxo'r ClassAva bir vaqtning o'zida quyidagi amalga oshirishga ega deb faraz qilaylik : ClassB
package com.journaldev.inheritance;
public class ClassC extends ClassA, ClassB{
    public void test(){
        //вызов метода родительского класса
        doSomething();
    }
}
E'tibor bering, usul ota-klassning test()usulini chaqiradi doSomething(), bu noaniqlikka olib keladi, chunki kompilyator qaysi superklass usulini chaqirish kerakligini bilmaydi. Ushbu vaziyatda sinfning meros diagrammasi shakli, qirrali olmosning konturiga o'xshashligi sababli, muammo "Olmos muammosi" deb nomlanadi. Bu Java bir nechta sinf merosini qo'llab-quvvatlamasligining asosiy sababidir. E'tibor bering, bir nechta sinf merosi bilan bog'liq bu muammo kamida bitta umumiy usulga ega bo'lgan uchta sinfda ham paydo bo'lishi mumkin.

Bir nechta meros va interfeyslar

Siz har doim "sinflar o'rtasida bir nechta meros qo'llab-quvvatlanmaydi" deb aytayotganimni payqadingiz, lekin u interfeyslar orasida qo'llab-quvvatlanadi. Oddiy misol quyida ko'rsatilgan: InterfaceA.java
package com.journaldev.inheritance;
public interface InterfaceA {

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

public interface InterfaceB {

    public void doSomething();
}
E'tibor bering, ikkala interfeys ham bir xil nomdagi usulga ega. Keling, ikkala interfeysdan meros bo'lgan interfeysga egamiz deylik. InterfaceC.java
package com.journaldev.inheritance;

public interface InterfaceC extends InterfaceA, InterfaceB {

    //метод, с тем же названием описан в  InterfaceA и InterfaceB
    public void doSomething();
Bu erda hamma narsa ideal, chunki interfeyslar faqat usulning zaxirasi/tavsifidir va usulning o'zi ushbu interfeyslarni amalga oshiradigan aniq sinfda bo'ladi, shuning uchun interfeyslarning ko'p merosxo'rligi bilan noaniqlikka duch kelishning imkoni yo'q. Shuning uchun Java-dagi sinflar bir nechta interfeyslardan meros bo'lishi mumkin. Keling, buni quyidagi misol bilan ko'rsatamiz. 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();
    }
}
Siz har safar supersinf yoki interfeysda tasvirlangan usulni bekor qilganimda @Override izohidan foydalanayotganimni payqagandirsiz. Bu uchta o'rnatilgan Java izohlaridan biri bo'lib, usullarni bekor qilishda har doim undan foydalanishingiz kerak.

Najot sifatida kompozitsiya

methodA()Xo'sh, agar biz sinf ClassAva methodB()sinf ClassBfunktsiyasidan foydalanmoqchi bo'lsak nima bo'ladi ClassС? Buning yechimi kompozitsiya bo'lishi mumkin - bu ClassCikkala sinf usullarini amalga oshiradigan ClassAva ob'ektlardan biri uchun ClassBamalga oshirishga ega bo'lgan qayta yozilgan 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();
    }
}

Tarkibmi yoki merosmi?

Merosdan ko'ra kompozitsiyadan foydalanish yaxshi Java dasturlash amaliyotidir. Biz ushbu yondashuv foydasiga ba'zi jihatlarni ko'rib chiqamiz.
  1. Faraz qilaylik, bizda ota-ona toifalarining quyidagi kombinatsiyasi mavjud:

    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;
        }
    }

    Yuqoridagi kod kompilyatsiya qiladi va yaxshi ishlaydi, lekin agar ClassCu boshqacha tarzda amalga oshirilgan bo'lsa nima bo'ladi:

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

    E'tibor bering, usul test()allaqachon avlod sinfida mavjud, ammo boshqa turdagi natijani qaytaradi. Endi ClassD, agar siz IDE dan foydalansangiz, u kompilyatsiya qilinmaydi. Sizga nasl yoki supersinfda qaytish turini o'zgartirish tavsiya etiladi.

    Keling, sinflarning ko'p darajali merosi mavjud bo'lgan va bizning o'zgarishlarimiz uchun superklass mavjud bo'lmagan vaziyatni tasavvur qilaylik. Endi, kompilyatsiya xatosidan xalos bo'lish uchun bizda subklass usulining imzosini yoki nomini o'zgartirishdan boshqa variantimiz yo'q. Shuningdek, biz ushbu usul chaqirilgan barcha joylarga o'zgartirish kiritishimiz kerak bo'ladi. Shunday qilib, meros bizning kodimizni mo'rt qiladi.

    Yuqorida tavsiflangan muammo kompozitsiyada hech qachon yuzaga kelmaydi va shuning uchun ikkinchisini merosga afzal ko'radi.

  2. Meros bilan bog'liq navbatdagi muammo shundaki, biz ota-onaning barcha usullarini mijozga ochib beramiz. Va agar superklass juda to'g'ri ishlab chiqilmagan bo'lsa va xavfsizlik teshiklari mavjud bo'lsa. Keyin, biz kichik sinfimizni amalga oshirishda xavfsizlikka to'liq g'amxo'rlik qilsak ham, biz hali ham ota-sinfning noto'g'ri bajarilishiga bog'liq bo'lamiz.

    Tarkibi bizga superklass usullariga boshqariladigan kirishni ta'minlashda yordam beradi, meros esa uning usullari ustidan hech qanday nazoratni saqlamaydi. Bu ham merosga nisbatan kompozitsiyaning asosiy afzalliklaridan biridir.

  3. Kompozitsiyaning yana bir afzalligi shundaki, u usullarni chaqirishda moslashuvchanlikni qo'shadi. Yuqorida tavsiflangan sinfni amalga oshirish ClassCoptimal emas va chaqirilgan usulga erta bog'lanishdan foydalanadi. Minimal o'zgarishlar bizga qo'ng'iroq qilish usulini moslashuvchan qilish va kech bog'lash imkonini beradi (ish vaqtida bog'lash).

    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();
        }
    }

    Yuqoridagi dastur ko'rsatadi:

    doSomething implementation of A
    doSomething implementation of B

    Usul chaqirishdagi bunday moslashuvchanlik meros bilan ko'rinmaydi, bu kompozitsiyani eng yaxshi yondashuvga aylantiradi.

  4. Kompozitsiya holatida birliklarni sinovdan o'tkazish osonroq, chunki biz bilamizki, supersinfda qo'llaniladigan barcha usullar uchun biz testlarni bekor qilishimiz mumkin, meros bo'lganda esa biz yuqori sinfga bog'liqmiz va ota-klassning usullari qanday ekanligini bilmaymiz. foydalaniladi. Shunday qilib, meros tufayli biz superklassning barcha usullarini sinab ko'rishimiz kerak, bu keraksiz ishdir.

    Ideal holda, meros faqat ota-onalar va bolalar sinflari uchun " is-a " munosabati to'g'ri bo'lganda ishlatilishi kerak , aks holda kompozitsiyaga ustunlik berish kerak.

Asl maqola
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION