Vraag Liever samenstelling dan overerving?


Waarom liever compositie dan overerving? Welke wisselwerking zijn er voor elke aanpak? Wanneer kies je voor overerving boven compositie?


1348
2017-09-08 01:58


oorsprong


antwoorden:


Geef de voorkeur aan compositie via overerving, omdat deze beter kneedbaar / gemakkelijk later te wijzigen is, maar gebruik geen compositie-altijd aanpak. Met compositie is het eenvoudig om gedrag te veranderen tijdens het vliegen met Dependency Injection / Setters. Overname is stijver omdat de meeste talen u niet toestaan ​​om af te leiden van meer dan één type. Dus de gans is min of meer gekookt zodra je afgeleid bent van TypeA.

Mijn zuurtest voor het bovenstaande is:

  • Wil TypeB de volledige interface (alle publieke methoden niet minder) van TypeA zodanig openbaar maken dat TypeB kan worden gebruikt waar TypeA wordt verwacht? Duidt op Erfenis.

bijv. Een Cessna-dubbeldekker zal de volledige interface van een vliegtuig blootleggen, zo niet meer. Dus dat maakt het geschikt om af te leiden van het vliegtuig.

  • Wil TypeB slechts een deel / een deel van het gedrag zichtbaar maken door TypeA? Geeft aan dat er behoefte aan is Samenstelling. 

bijv. Een vogel heeft mogelijk alleen het vlieggedrag van een vliegtuig nodig. In dit geval is het logisch om het uit te pakken als een interface / klasse / beide en het lid te maken van beide klassen.

Bijwerken: Ik kwam net terug op mijn antwoord en het lijkt nu dat het onvolledig is zonder een specifieke vermelding van Barbara Liskov's Liskov-vervangingsprincipe als een test voor 'Moet ik van dit type erfelijk zijn?'


1010
2017-09-10 03:04



Beschouw containment als een heeft een relatie. Een auto "heeft een" motor, een persoon "heeft een" naam, enz.

Zie overerving als een is een relatie. Een auto "is een" voertuig, een persoon "is een" zoogdier, enz.

Ik neem geen eer aan voor deze aanpak. Ik heb het rechtstreeks uit de Tweede editie van Code voltooid door Steve McConnell, Paragraaf 6.3.


347
2017-09-08 02:09



Als je het verschil begrijpt, is het makkelijker uit te leggen.

Procedurecode

Een voorbeeld hiervan is PHP zonder het gebruik van klassen (met name voor PHP5). Alle logica is gecodeerd in een reeks functies. U kunt andere bestanden met helperfuncties opnemen enzovoort en uw bedrijfslogica uitvoeren door gegevens in functies door te geven. Dit kan heel moeilijk te beheren zijn naarmate de applicatie groeit. PHP5 probeert dit te verhelpen door meer objectgeoriënteerd ontwerp aan te bieden.

Erfenis

Dit moedigt het gebruik van klassen aan. Overerving is een van de drie principes van OO-ontwerp (overerving, polymorfisme, inkapseling).

class Person {
   String Title;
   String Name;
   Int Age
}

class Employee : Person {
   Int Salary;
   String Title;
}

Dit is erfenis op het werk. De werknemer "is een" persoon of erft van persoon. Alle erfrechtrelaties zijn 'is-a'-relaties. Medewerker stelt ook de eigenschap Title in de schaduw van de persoon, wat betekent dat Employee.Title de titel voor de werknemer en niet de persoon retourneert.

Samenstelling

Compositie heeft de voorkeur boven overerving. Om het simpel te zeggen, zou je:

class Person {
   String Title;
   String Name;
   Int Age;

   public Person(String title, String name, String age) {
      this.Title = title;
      this.Name = name;
      this.Age = age;
   }

}

class Employee {
   Int Salary;
   private Person person;

   public Employee(Person p, Int salary) {
       this.person = p;
       this.Salary = salary;
   }
}

Person johnny = new Person ("Mr.", "John", 25);
Employee john = new Employee (johnny, 50000);

Samenstelling is meestal een relatie "heeft een" of "gebruikt een". Hier heeft de klasse Werknemers een persoon. Het neemt niet van de Persoon over, maar krijgt in plaats daarvan het Persoon-object doorgegeven, wat de reden is waarom het "een" Persoon heeft.

Compositie over Erfenis

Stel nu dat u een managerstype wilt maken, zodat u eindigt met:

class Manager : Person, Employee {
   ...
}

Dit voorbeeld werkt prima, maar wat als zowel persoon als werknemer hebben verklaard Title? Moet Manager.Titel terugkeren naar "Manager of Operations" of "Mr."? Onder de compositie kan deze ambiguïteit beter worden behandeld:

Class Manager {
   public Title;
   public Manager(Person p, Employee e)
   {
      this.Title = e.Title;
   }
}

Het Manager-object is samengesteld als een werknemer en een persoon. Het gedrag van de titel is overgenomen van de medewerker. Deze expliciete compositie verwijdert ambiguïteit onder andere en je zult minder fouten tegenkomen.


175
2018-05-21 07:54



Met alle onmiskenbare voordelen die door overerving worden geboden, zijn hier enkele nadelen.

Nadelen van Inheritance:

  1. U kunt de implementatie die tijdens runtime wordt overgeërfd van superklassen niet wijzigen (uiteraard omdat inheritance tijdens compileren is gedefinieerd).
  2. Overerving stelt een subklasse bloot aan details van de klassenimplementatie van de ouder. Daarom wordt vaak gezegd dat inheritance encapsulation verbreekt (in zekere zin dat u zich echt moet richten op interfaces, maar niet op implementatie, dus hergebruik door subclassificatie verdient niet altijd de voorkeur).
  3. De strakke koppeling door overerving maakt de implementatie van een subklasse zeer gebonden aan de implementatie van een superklasse die elke wijziging in de ouderimplementatie ertoe zal nopen de subklasse te veranderen.
  4. Overmatig hergebruik door subklassen kan de overervingsstapel erg diep en erg verwarrend maken.

Aan de andere kant Object samenstelling wordt tijdens runtime gedefinieerd door objecten die verwijzingen naar andere objecten ontvangen. In een dergelijk geval zullen deze objecten elkaars beschermde gegevens nooit kunnen bereiken (geen onderbreking door inkapseling) en zullen ze gedwongen worden om elkaars interface te respecteren. En in dit geval zullen implementatieafhankelijkheden ook veel minder zijn dan in geval van overerving.


91
2018-05-21 08:34



Een andere, erg pragmatische reden, om compositie te verkiezen boven overerving heeft te maken met je domeinmodel en het in kaart te brengen in een relationele database. Het is erg moeilijk om overerving aan het SQL-model toe te wijzen (je krijgt uiteindelijk allerlei hacky-oplossingen, zoals het maken van kolommen die niet altijd worden gebruikt, met behulp van weergaven, enzovoort). Sommige ORML's proberen hiermee om te gaan, maar het wordt altijd snel gecompliceerd. Compositie kan eenvoudig worden gemodelleerd door een foreign-key relatie tussen twee tabellen, maar de erfenis is veel moeilijker.


77
2017-09-08 02:48



Hoewel ik het in korte woorden eens ben met 'voorkeurssamenstelling boven overerving', klinkt het voor mij heel vaak als 'liever aardappel dan coca-cola'. Er zijn plaatsen voor overerving en plaatsen voor compositie. U moet het verschil begrijpen, dan zal deze vraag verdwijnen. Wat het echt betekent voor mij is "als je erfenis gaat gebruiken - denk opnieuw, de kans is groot dat je samenstelling nodig hebt".

Je moet liever aardappelen hebben dan coca cola als je wilt eten, en coca cola als je wilt drinken over aardappelen.

Het maken van een subklasse zou meer moeten zijn dan alleen een handige manier om superklasse-methoden aan te roepen. Gebruik overerving als subklasse "is-een" superklasse, zowel structureel als functioneel, als het kan worden gebruikt als superklasse en u dat gaat gebruiken. Als het niet het geval is - het is geen erfenis, maar iets anders. Compositie is wanneer je objecten uit een ander bestaan, of er een relatie mee hebben.

Dus voor mij lijkt het erop dat als iemand niet weet of hij vererving of samenstelling nodig heeft, het echte probleem is dat hij niet weet of hij wil drinken of eten. Denk meer aan uw probleemdomein, begrijp het beter.


64
2018-05-08 22:29



Overerving is behoorlijk verleidelijk, vooral vanuit procedureel-land en het ziet er vaak bedrieglijk elegant uit. Ik bedoel, alles wat ik moet doen is dit ene beetje functionaliteit toevoegen aan een andere klas, toch? Nou, een van de problemen is dat

overerving is waarschijnlijk de slechtste vorm van koppeling die je kunt hebben

Uw basisklasse breekt inkapseling door implementatiedetails bloot te leggen aan subklassen in de vorm van beveiligde leden. Dit maakt uw systeem rigide en kwetsbaar. De meer tragische fout is echter dat de nieuwe subklasse alle bagage en meningen van de overervingsketen met zich meebrengt.

Het artikel, Inheritance is Evil: The Epic Fail van de DataAnnotationsModelBinder, loopt hier een voorbeeld van door in C #. Het toont het gebruik van overerving wanneer compositie had moeten worden gebruikt en hoe het kon worden gerefactored.


54
2018-01-23 19:55