JavaRush /Java блогы /Random-KK /Java тіліндегі көп мұра. Құрамы мен тұқым қуалаушылықты с...
HonyaSaar
Деңгей
Москва

Java тіліндегі көп мұра. Құрамы мен тұқым қуалаушылықты салыстыру

Топта жарияланған
Біраз уақыт бұрын мен Java тіліндегі мұра, интерфейстер және композиция туралы бірнеше жазбалар жаздым. Бұл мақалада біз бірнеше мұраны қарастырамыз, содан кейін мұраға қарағанда композицияның артықшылықтары туралы білеміз.
Java тіліндегі көп мұра.  Құрамы мен тұқым қуалауын салыстыру – 1

Java тіліндегі бірнеше мұра

Бірнеше мұрагерлік - бірнеше ата-аналық сыныптары бар сыныптарды құру мүмкіндігі. C++ сияқты басқа танымал нысанға бағытталған тілдерден айырмашылығы, 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 бірнеше класс мұрасын қолдамауының басты себебі. Бірнеше класс мұрасы бар бұл мәселе кемінде бір жалпы әдісі бар үш сыныпта да орын алуы мүмкін екенін ескеріңіз.

Бірнеше мұра және интерфейстер

Сіз менің әрқашан «сыныптар арасында бірнеше мұраға қолдау көрсетілмейді» деп айтатынымды байқаған боларсыз, бірақ ол интерфейстер арасында қолдау көрсетеді. Қарапайым мысал төменде көрсетілген: 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()сынып функциясын қолданғымыз келсе ClassBше ClassС? Бұл шешім композиция болуы мүмкін - ClassCекі класс әдісін де жүзеге асыратын ClassAжәне an objectілердің біреуі үшін 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 пайдалансаңыз, ол компиляцияланбайды. Сізге ұрпақтағы немесе суперсыныптағы қайтару түрін өзгерту ұсынылады.

    Енді сыныптардың көп деңгейлі мұрасы бар жағдайды елестетіп көрейік және суперкласс біздің өзгертулеріміз үшін қол жетімді емес. Енді компиляция қателігінен құтылу үшін бізде қосалқы класс әдісінің қолтаңбасын немесе атауын өзгертуден басқа опциялар жоқ. Сондай-ақ бұл әдіс шақырылған барлық жерлерге өзгертулер енгізуге тура келеді. Осылайша, мұрагерлік біздің codeты сынғыш етеді.

    Жоғарыда сипатталған мәселе композиция жағдайында ешқашан болмайды, сондықтан мұрагерлікке соңғысын артықшылық береді.

  2. Мұрагерлікпен байланысты келесі мәселе - біз клиентке ата-ананың барлық әдістерін ашамыз. Ал егер суперкласс өте дұрыс жобаланбаған болса және қауіпсіздік саңылаулары болса. Содан кейін, біз ішкі сыныпты жүзеге асыруда қауіпсіздікті толығымен қамтамасыз етсек те, біз әлі де ата-аналық сыныптың қате орындалуына тәуелді боламыз.

    Композиция бізге суперкласс әдістеріне басқарылатын қолжетімділікті қамтамасыз етуге көмектеседі, ал мұрагерлік оның әдістеріне ешқандай бақылау жүргізбейді. Бұл да мұрагерлікке қарағанда композицияның басты артықшылықтарының бірі.

  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

    Әдістерді шақырудағы бұл икемділік мұрагерлікпен байқалмайды, бұл композицияны ең жақсы тәсіл етеді.

  4. Композиция жағдайында бірліктерді тестілеу оңайырақ, өйткені біз суперсыныпта қолданылатын барлық әдістер үшін сынақтарды тоқтата алатынымызды білеміз, ал мұрагерлікте біз суперклассқа қатты тәуелдіміз және ата-аналық сыныптың әдістерін білмейміз. қолданылатын болады. Сонымен, тұқым қуалаушылыққа байланысты біз суперкласстың барлық әдістерін сынауға мәжбүр боламыз, бұл қажетсіз жұмыс.

    Ең дұрысы, мұра тек ата-ана және еншілес сыныптар үшін " is-a " қатынасы дұрыс болғанда ғана пайдаланылуы керек , әйтпесе композицияны таңдау керек.

Түпнұсқа мақала
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION