JavaRush /Java Blog /Random-TL /Maramihang pamana sa Java. Paghahambing ng komposisyon at...
HonyaSaar
Antas
Москва

Maramihang pamana sa Java. Paghahambing ng komposisyon at mana

Nai-publish sa grupo
Ilang oras na ang nakalipas nagsulat ako ng ilang mga post tungkol sa pamana, mga interface at komposisyon sa Java. Sa artikulong ito, titingnan natin ang maramihang pamana at pagkatapos ay matutunan ang tungkol sa mga benepisyo ng komposisyon kaysa sa pamana.
Maramihang pamana sa Java.  Paghahambing ng komposisyon at mana - 1

Maramihang Pamana sa Java

Ang multiple inheritance ay ang kakayahang lumikha ng mga klase na may maraming parent na klase. Hindi tulad ng iba pang sikat na object-oriented na wika gaya ng C++, hindi sinusuportahan ng Java ang multiple class inheritance. Hindi niya ito sinusuportahan dahil sa posibilidad na makatagpo ng "problema sa brilyante" at sa halip ay mas pinipiling magbigay ng ilang uri ng komprehensibong diskarte upang malutas ito, gamit ang pinakamahusay na mga opsyon na makakamit natin ang katulad na resulta ng mana.

"Ang Problema sa Diamond"

Upang maunawaan ang problema sa brilyante nang mas simple, ipagpalagay natin na ang maramihang pamana ay sinusuportahan sa Java. Sa kasong ito, makakakuha tayo ng mga klase na may hierarchy na ipinapakita sa figure sa ibaba. hierarchy ng klase ng brilyanteIpagpalagay natin na iyon SuperClassay isang abstract na klase na naglalarawan ng isang tiyak na pamamaraan, at ang mga klase ClassAat ClassBmga tunay na klase. 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(){
    }
}
Ngayon, ipagpalagay natin na ang klase ClassCay nagmamana mula sa ClassAat ClassBsa parehong oras, at sa parehong oras ay may sumusunod na pagpapatupad:
package com.journaldev.inheritance;
public class ClassC extends ClassA, ClassB{
    public void test(){
        //вызов метода родительского класса
        doSomething();
    }
}
Tandaan na ang pamamaraan test()ay tumatawag ng isang pamamaraan doSomething()ng parent class, na hahantong sa kalabuan dahil hindi alam ng compiler kung aling superclass na pamamaraan ang dapat tawagan. Dahil sa hugis ng class inheritance diagram sa sitwasyong ito, na kahawig ng outline ng faceted diamond, ang problema ay tinatawag na "Diamond Problem". Ito ang pangunahing dahilan kung bakit hindi sinusuportahan ng Java ang multiple class inheritance. Tandaan na ang problemang ito sa multiple class inheritance ay maaari ding mangyari sa tatlong klase na may hindi bababa sa isang karaniwang paraan.

Maramihang inheritance at interface

Maaaring napansin mo na lagi kong sinasabi ang "multiple inheritance is not supported between classes", ngunit ito ay sinusuportahan sa pagitan ng mga interface. Ang isang simpleng halimbawa ay ipinapakita sa ibaba: InterfaceA.java
package com.journaldev.inheritance;
public interface InterfaceA {

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

public interface InterfaceB {

    public void doSomething();
}
Pansinin na ang parehong mga interface ay may isang pamamaraan na may parehong pangalan. Ngayon sabihin nating mayroon tayong interface na nagmamana mula sa parehong mga interface. InterfaceC.java
package com.journaldev.inheritance;

public interface InterfaceC extends InterfaceA, InterfaceB {

    //метод, с тем же названием описан в  InterfaceA и InterfaceB
    public void doSomething();
Dito, ang lahat ay perpekto, dahil ang mga interface ay isang reserbasyon/paglalarawan lamang ng isang pamamaraan, at ang pagpapatupad ng pamamaraan mismo ay nasa kongkretong klase na nagpapatupad ng mga interface na ito, kaya walang posibilidad na makatagpo ng kalabuan na may maraming pamana ng mga interface. Ito ang dahilan kung bakit ang mga klase sa Java ay maaaring magmana mula sa maraming mga interface. Ipakita natin ito sa halimbawa sa ibaba. 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();
    }
}
Maaaring napansin mo na sa tuwing i-override ko ang isang pamamaraan na inilarawan sa isang superclass o sa isang interface, ginagamit ko ang @Override annotation. Ito ay isa sa tatlong built-in na Java annotation at dapat mong gamitin ito palagi kapag nag-o-override ng mga pamamaraan.

Komposisyon bilang kaligtasan

Paano kung gusto naming gumamit ng isang methodA()klase ClassAat pag-andar methodB()ng klase ClassBsa ClassС? Ang isang solusyon dito ay maaaring komposisyon - isang muling isinulat na bersyon ClassCna nagpapatupad ng parehong mga pamamaraan ng klase ClassAat ClassBmayroon ding pagpapatupad doSomething()para sa isa sa mga bagay. 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();
    }
}

Komposisyon o pamana?

Ito ay isang mahusay na kasanayan sa Java programming upang samantalahin ang komposisyon kaysa sa mana. Titingnan natin ang ilang aspeto na pabor sa diskarteng ito.
  1. Ipagpalagay na mayroon tayong sumusunod na kumbinasyon ng mga klase ng magulang at tagapagmana:

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

    Ang code sa itaas ay nag-compile at gumagana nang maayos, ngunit paano kung ClassCiba itong ipinatupad:

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

    Tandaan na ang pamamaraan test()ay umiiral na sa descendant class, ngunit nagbabalik ng resulta ng ibang uri. Ngayon ClassD, kung sakaling gumagamit ka ng IDE, hindi ito mag-compile. Papayuhan kang baguhin ang uri ng pagbabalik sa descendant o superclass.

    Ngayon isipin natin ang isang sitwasyon kung saan mayroong multi-level inheritance ng mga klase at hindi available ang superclass para sa ating mga pagbabago. Ngayon, para maalis ang error sa compilation, wala kaming ibang opsyon kundi baguhin ang signature o pangalan ng subclass method. Kakailanganin din nating gumawa ng mga pagbabago sa lahat ng lugar kung saan tinawag ang pamamaraang ito. Kaya, ginagawang malutong ng pamana ang ating code.

    Ang problemang inilarawan sa itaas ay hindi kailanman nangyayari sa kaso ng komposisyon, at samakatuwid ay ginagawang mas pinipili ang huli kaysa sa mana.

  2. Ang susunod na problema sa mana ay ilantad namin ang lahat ng mga pamamaraan ng magulang sa kliyente. At kung ang superclass ay hindi idinisenyo nang tama at naglalaman ng mga butas sa seguridad. Pagkatapos, kahit na lubos nating pinangangalagaan ang seguridad sa pagpapatupad ng ating subclass, aasa pa rin tayo sa maling pagpapatupad ng parent class.

    Tinutulungan tayo ng komposisyon sa pagbibigay ng kontroladong pag-access sa mga pamamaraan ng isang superclass, samantalang ang mana ay hindi nagpapanatili ng anumang kontrol sa mga pamamaraan nito. Ito rin ay isa sa mga pangunahing bentahe ng komposisyon kaysa sa mana.

  3. Ang isa pang benepisyo ng komposisyon ay nagdaragdag ito ng kakayahang umangkop kapag tumatawag sa mga pamamaraan. Ang pagpapatupad ng klase ClassCna inilarawan sa itaas ay hindi optimal at gumagamit ng maagang pagbubuklod sa tinatawag na pamamaraan. Ang mga kaunting pagbabago ay magbibigay-daan sa amin na gawing flexible ang paraan ng pagtawag at magbibigay-daan para sa late binding (binding sa runtime).

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

    Ipapakita ng program sa itaas ang:

    doSomething implementation of A
    doSomething implementation of B

    Ang kakayahang umangkop na ito sa paraan ng pagtawag ay hindi nakikita sa mana, na ginagawang komposisyon ang pinakamahusay na diskarte.

  4. Ang pagsubok sa yunit ay mas madali sa kaso ng komposisyon dahil alam namin na para sa lahat ng mga pamamaraan na ginagamit sa superclass maaari naming i-stub ang mga pagsubok, habang sa pamana kami ay umaasa nang malaki sa superclass at hindi alam kung paano ang mga pamamaraan ng parent class gagamitin. Kaya, dahil sa pamana, kailangan nating subukan ang lahat ng mga pamamaraan ng superclass, na hindi kinakailangang gawain.

    Sa isip, ang mana ay dapat lamang gamitin kapag ang " is-a " na relasyon ay totoo para sa mga klase ng magulang at anak, kung hindi, ang komposisyon ay dapat na mas gusto.

Orihinal na artikulo
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION