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. Faraz qilaylik,SuperClass
bu ma'lum bir usulni tavsiflovchi mavhum sinf, va sinflar
ClassA
va
ClassB
haqiqiy 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
ClassC
merosxo'r
ClassA
va 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
ClassA
va
methodB()
sinf
ClassB
funktsiyasidan foydalanmoqchi bo'lsak nima bo'ladi
ClassС
? Buning yechimi kompozitsiya bo'lishi mumkin - bu
ClassC
ikkala sinf usullarini amalga oshiradigan
ClassA
va ob'ektlardan biri uchun
ClassB
amalga 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.-
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
ClassC
u 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. EndiClassD
, 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.
-
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.
-
Kompozitsiyaning yana bir afzalligi shundaki, u usullarni chaqirishda moslashuvchanlikni qo'shadi. Yuqorida tavsiflangan sinfni amalga oshirish
ClassC
optimal 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.
-
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.
GO TO FULL VERSION