JavaRush /Java блогу /Random-KY /Javaда бир нече мурас. Курамды жана тукум куучулукту салы...
HonyaSaar
Деңгээл
Москва

Javaда бир нече мурас. Курамды жана тукум куучулукту салыштыруу

Группада жарыяланган
Бир нече убакыт мурун мен Java'да мурас, интерфейстер жана композиция жөнүндө бир нече пост жаздым. Бул макалада биз бир нече тукум куучулукту карап чыгабыз, андан кийин мураска караганда композициянын артыкчылыктары жөнүндө билебиз.
Javaда бир нече мурас.  Курамды жана тукум куучулукту салыштыруу - 1

Javaдагы бир нече мурас

Бир нече тукум куучулук - бул бир нече ата-эне класстары бар класстарды түзүү мүмкүнчүлүгү. C++ сыяктуу башка популярдуу an objectиге багытталган тилдерден айырмаланып, Java бир нече класс мурасын колдобойт. Ал "бриллиант көйгөйүнө" туш болуу ыктымалдыгынан улам аны колдобойт жана анын ордуна биз ушундай мурастык натыйжага жетише ала турган эң жакшы варианттарды колдонуп, аны чечүү үчүн кандайдыр бир комплекстүү мамиле жасоону артык көрөт.

"Бриллиант маселеси"

Алмаз маселесин жөнөкөйраак түшүнүү үчүн, келгиле, Java-да бир нече тукум куучулук колдоого алынат деп коёлу. Бул учурда, биз төмөндөгү сүрөттө көрсөтүлгөн иерархия менен класстарды ала алабыз. Бул белгилүү бир методду сүрөттөгөн абстракттуу класс жана класстар жана чыныгы класстар алмаз класс иерархиясыдеп коёлу . SuperClass ClassA ClassB 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(){
    }
}
ClassCЭми, класс бир эле учурда мураска алат ClassAжана ClassBошол эле учурда төмөнкү ишке ээ деп ойлойлу :
package com.journaldev.inheritance;
public class ClassC extends ClassA, ClassB{
    public void test(){
        //вызов метода родительского класса
        doSomething();
    }
}
Метод ата-эне классынын test()ыкмасын чакырарын эске алыңыз doSomething(), бул түшүнүксүздүккө алып келет, анткени компилятор кайсы суперкласс ыкмасын чакыруу керектигин билбейт. Бул кырдаалда класстын тукум куучулук диаграммасынын формасына байланыштуу, ал кырдуу алмаздын контуруна окшош болгондуктан, маселе “Бриллиант маселеси” деп аталат. Бул Java бир нече класс мурасын колдоого албашынын негизги себеби. Көңүл буруңуз, бул көйгөй бир нече класстын мурастоосу менен, жок эле дегенде, бир жалпы ыкмасы бар үч класста да пайда болушу мүмкүн.

Бир нече мурас жана интерфейстер

Мен ар дайым "класстар арасында бир нече мурас колдоого алынbyte" деп айтканымды байкагандырсыз, бирок ал интерфейстер арасында колдоого алынат. Жөнөкөй мисал төмөндө көрсөтүлгөн: InterfaceA.java
package com.journaldev.inheritance;
public interface InterfaceA {

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

public interface InterfaceB {

    public void doSomething();
}
Эки интерфейстин бирдей аталыштагы ыкмасы бар экенин байкаңыз. Эми бизде эки интерфейстен тең мураска алынган интерфейс бар дейли. InterfaceC.java
package com.journaldev.inheritance;

public interface InterfaceC extends InterfaceA, InterfaceB {

    //метод, с тем же названием описан в  InterfaceA и InterfaceB
    public void doSomething();
Бул жерде бардыгы идеалдуу, анткени интерфейстер методдун резервден/сүрөттөмөсү гана, ал эми методдун өзү ишке ашырылышы бул интерфейстерди ишке ашырган конкреттүү класста болот, андыктан интерфейстердин көп мурастоосу менен бүдөмүктүккө туш болуу мүмкүнчүлүгү жок. Мына ошондуктан Javaдагы класстар бир нече интерфейстерден мурасталышы мүмкүн. Аны төмөндөгү мисал менен көрсөтөлү. 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();
    }
}
Сиз суперкласста же интерфейсте сүрөттөлгөн ыкманы жокко чыгарган сайын @Override annotationсын колдонгонумду байкагандырсыз. Бул үч камтылган Java annotationсынын бири жана сиз аны ар дайым ыкмаларды жокко чыгарууда колдонушуңуз керек.

Курамы куткаруу катары

Анда methodA()классты ClassAжана methodB()класс функциясын колдонгубуз келсе эмне болот ? Мунун чечими композиция болушу мүмкүн - класстык методдорду тең ишке ашырган жана an objectтердин бири үчүн ишке ашырууга ээ болгон кайра жазылган version. ClassB ClassС ClassC ClassA ClassB 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();
    }
}

Курамбы же мураспы?

Мураска караганда композицияны пайдалануу жакшы Java программалоо практикасы. Биз бул ыкманын пайдасына кээ бир аспектилерин карап чыгабыз.
  1. Бизде ата-эне-мураскор класстарынын төмөнкү айкалышы бар дейли:

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

    Жогорудагы code түзүлөт жана жакшы иштейт, бирок ClassCал башкача ишке ашырылсачы?

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

    Метод test()урпак классында бар экенин, бирок башка түрдөгү натыйжаны кайтарарын эске алыңыз. Эми ClassD, эгер сиз IDE колдонуп жатсаңыз, ал компиляцияланbyte. Сизге тукумдагы же суперкласстагы кайтаруу түрүн өзгөртүү сунушталат.

    Эми класстардын көп деңгээлдүү мурастоосу бар жана суперкласс биздин өзгөртүүлөрүбүз үчүн жеткorктүү эмес жагдайды элестетип көрөлү. Эми, компиляция катасынан кутулуу үчүн, бизде подкласс ыкмасынын кол тамгасын же атын өзгөртүүдөн башка жолдорубуз жок. Ошондой эле бул ыкманы чакырган бардык жерлерге өзгөртүүлөрдү киргизүүгө туура келет. Ошентип, мурас биздин codeду морт кылат.

    Жогоруда сүрөттөлгөн маселе эч качан курамында пайда болбойт, демек, мураска экинчисин артыкчылыктуу кылат.

  2. Мурас боюнча кийинки көйгөй, биз кардарга ата-эненин бардык ыкмаларын ачыкка чыгарабыз. Ал эми суперкласс өтө туура эмес иштелип чыккан жана коопсуздук тешиктерин камтыган болсо. Андан кийин, биз подклассыбызды ишке ашырууда коопсуздукту толук кам көрөбүз да, биз дагы эле ата-эне класстын кемчorктерин ишке ашырууга көз каранды болобуз.

    Композиция бизге суперкласстын методдоруна башкарылуучу жеткorкти камсыз кылууга жардам берет, ал эми мурас анын ыкмаларына эч кандай көзөмөл жүргүзбөйт. Бул да мураска караганда курамынын негизги артыкчылыктарынын бири болуп саналат.

  3. Композициянын дагы бир артыкчылыгы - бул ыкмаларды чакырганда ийкемдүүлүктү кошот. Жогоруда сүрөттөлгөн классты ишке ашыруу ClassCоптималдуу эмес жана чакырылган ыкмага эрте байланышты колдонот. Минималдуу өзгөртүүлөр бизге чалуу ыкмасын ийкемдүү кылууга жана кеч байланыштырууга мүмкүндүк берет (иштөө убагында милдеттүү).

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

    Жогорудагы программа төмөнкүнү көрсөтөт:

    doSomething implementation of A
    doSomething implementation of B

    Методду чакыруудагы бул ийкемдүүлүк мурастоодо байкалbyte, бул композицияны эң жакшы ыкма кылат.

  4. Композицияда бирдикти тестирлөө жеңorрээк, анткени биз суперкласста колдонулган бардык ыкмалар үчүн тесттерди жокко чыгара аларыбызды билебиз, ал эми мурастоодо биз суперкласска көп көз карандыбыз жана ата-эне класстын ыкмалары кандай экенин билбейбиз. колдонулат. Ошентип, мураска байланыштуу, биз суперкласстын бардык ыкмаларын сынап көрүшүбүз керек, бул керексиз жумуш.

    Идеалында, мурас ата-эне жана бала класстары үчүн “ болгон-a ” байланышы туура болгондо гана колдонулушу керек , антпесе, курамы артыкчылыктуу болушу керек.

Оригиналдуу макала
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION