Czy skład i dziedzictwo są takie same? Jeśli chcę zaimplementować wzorzec kompozycji, jak mogę to zrobić w Javie?
Czy skład i dziedzictwo są takie same? Jeśli chcę zaimplementować wzorzec kompozycji, jak mogę to zrobić w Javie?
Odpowiedzi:
Są absolutnie różne. Dziedziczenie to relacja „jest-a” . Kompozycja jest „has-a” .
Komponujesz, mając instancję innej klasy C
jako pole swojej klasy, zamiast rozszerzać C
. Dobry przykład, w którym kompozycja byłaby o wiele lepsza niż dziedziczenie java.util.Stack
, która obecnie się rozszerza java.util.Vector
. To jest teraz uważane za błąd. Wektor stosu to „NIE-NIE” ; nie powinno się zezwalać na dowolne wstawianie i usuwanie elementów. Zamiast tego powinna to być kompozycja.
Niestety jest już za późno, aby naprawić ten błąd projektowy, ponieważ zmiana hierarchii dziedziczenia spowodowałaby uszkodzenie kompatybilności z istniejącym kodem. Gdyby Stack
używane zamiast kompozycji dziedziczenia, można zawsze modyfikowane, inną strukturę danych bez naruszania API .
Bardzo polecam książkę Josha Blocha Effective Java 2nd Edition
Dobry projekt obiektowy nie polega na swobodnym rozszerzaniu istniejących klas. Twoim pierwszym instynktem powinno być komponowanie.
Zobacz też:
Kompozycja oznacza HAS A
DziedziczenieIS A
Example
: Samochód ma silnik, a samochód to samochód
W programowaniu jest to przedstawiane jako:
class Engine {} // The Engine class.
class Automobile {} // Automobile class which is parent to Car class.
class Car extends Automobile { // Car is an Automobile, so Car class extends Automobile class.
private Engine engine; // Car has an Engine so, Car class has an instance of Engine class as its member.
}
:-/
type
pole typuEnum
Jak dziedziczenie może być niebezpieczne?
Weźmy przykład
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1) Jak jasno wynika z powyższego kodu, klasa Y ma bardzo silne sprzężenie z klasą X. Jeśli coś zmieni się w nadklasie X, Y może się dramatycznie złamać. Załóżmy, że w przyszłości klasa X implementuje metodę pracy z podpisem poniżej
public int work(){
}
Zmiany dokonano w klasie X, ale uniemożliwi ona kompilację klasy Y. Tak więc tego rodzaju zależność może wzrosnąć do dowolnego poziomu i może być bardzo niebezpieczna. Za każdym razem, gdy nadklasa może nie mieć pełnej widoczności kodu we wszystkich swoich podklasach, podklasa może ciągle zauważać, co dzieje się w nadklasie. Musimy więc unikać tego silnego i niepotrzebnego połączenia.
Jak kompozycja rozwiązuje ten problem?
Zobaczmy, przeglądając ten sam przykład
public class X{
public void do(){
}
}
Public Class Y{
X x = new X();
public void work(){
x.do();
}
}
Tutaj tworzymy odwołanie do klasy X w klasie Y i wywołujemy metodę klasy X, tworząc instancję klasy X. Teraz całe to silne sprzężenie zniknęło. Nadklasa i podklasa są teraz wysoce od siebie niezależne. Klasy mogą swobodnie dokonywać zmian, które były niebezpieczne w sytuacji spadkowej.
2) Druga bardzo dobra zaleta kompozycji, ponieważ zapewnia elastyczność wywoływania metod, na przykład:
class X implements R
{}
class Y implements R
{}
public class Test{
R r;
}
W klasie Test przy użyciu referencji r mogę wywoływać metody klasy X, a także klasy Y. Ta elastyczność nigdy nie była dziedziczona
3) Kolejna wielka zaleta: testowanie jednostkowe
public class X {
public void do(){
}
}
Public Class Y {
X x = new X();
public void work(){
x.do();
}
}
W powyższym przykładzie, jeśli stan instancji x nie jest znany, można go łatwo wykpić przy użyciu niektórych danych testowych, a wszystkie metody można łatwo przetestować. Nie było to możliwe w przypadku dziedziczenia, ponieważ byłeś silnie zależny od nadklasy, aby uzyskać stan instancji i wykonać dowolną metodę.
4) Kolejnym dobrym powodem, dla którego powinniśmy unikać dziedziczenia, jest to, że Java nie obsługuje wielokrotnego dziedziczenia.
Weźmy przykład, aby to zrozumieć:
Public class Transaction {
Banking b;
public static void main(String a[])
{
b = new Deposit();
if(b.deposit()){
b = new Credit();
c.credit();
}
}
}
Dobrze wiedzieć :
kompozycję można łatwo osiągnąć w czasie wykonywania, a dziedziczenie zapewnia jej funkcje w czasie kompilacji
kompozycja jest również znana jako relacja HAS-A, a dziedziczenie jest również znane jako relacja IS-A
Niech więc nawyk zawsze woli preferować kompozycję niż dziedziczenie z różnych powyższych powodów.
Odpowiedź udzielona przez @Michaela Rodriguesa jest nieprawidłowa (przepraszam; nie jestem w stanie komentować bezpośrednio) i może powodować pewne zamieszanie.
Implementacja interfejsu jest formą dziedziczenia ... kiedy implementujesz interfejs, nie tylko dziedziczysz wszystkie stałe, ale zobowiązujesz obiekt, aby był typu określonego przez interfejs; wciąż jest to relacja „ jest-a ”. Jeśli samochód implementuje funkcję Fillable , samochód „ is-a ” Fillable i może być używany w kodzie wszędzie tam, gdzie chcesz użyć Fillable .
Skład zasadniczo różni się od dziedziczenia. Korzystając z kompozycji, (jak zauważają inne odpowiedzi) tworzysz relację „ ma-a ” między dwoma obiektami, w przeciwieństwie do relacji „ jest-a ”, którą tworzysz, gdy korzystasz z dziedziczenia .
Tak więc z przykładów samochodów w innych pytaniach, gdybym chciał powiedzieć, że samochód ma „zbiornik paliwa”, użyłbym kompozycji w następujący sposób:
public class Car {
private GasTank myCarsGasTank;
}
Mam nadzieję, że rozwiąże to wszelkie nieporozumienia.
Dziedziczenie wydobywa relację IS-A . Kompozycja wydobywa relację HAS-A . Wzorzec strategii wyjaśnia, że Kompozycję należy stosować w przypadkach, gdy istnieją rodziny algorytmów definiujących określone zachowanie.
Klasycznym przykładem jest klasa kaczki, która realizuje zachowanie podczas lotu.
public interface Flyable{
public void fly();
}
public class Duck {
Flyable fly;
public Duck(){
fly = new BackwardFlying();
}
}
W ten sposób możemy mieć wiele klas, które implementują latanie, np .:
public class BackwardFlying implements Flyable{
public void fly(){
Systemout.println("Flies backward ");
}
}
public class FastFlying implements Flyable{
public void fly(){
Systemout.println("Flies 100 miles/sec");
}
}
Gdyby chodziło o dziedziczenie, mielibyśmy dwie różne klasy ptaków, które realizują funkcję much w kółko. Tak więc dziedziczenie i skład są zupełnie inne.
Kompozycja jest taka, jak się wydaje - tworzysz obiekt, wkładając części.
EDYCJA reszta odpowiedzi jest błędnie oparta na następującej przesłance.
Dokonuje się tego za pomocą interfejsów.
Na przykład, korzystając z Car
powyższego przykładu,
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
Zatem za pomocą kilku standardowych elementów teoretycznych możesz zbudować swój obiekt. Twoim zadaniem jest zatem określić, w jaki sposób House
chroni pasażerów i jak Car
chroni pasażerów.
Dziedziczenie jest jak na odwrót. Zaczynasz od pełnego (lub pół-pełnego) obiektu i zamieniasz lub zastępujesz różne bity, które chcesz zmienić.
Na przykład MotorVehicle
może pochodzić z Fuelable
metody i Drive
metody. Możesz opuścić metodę Fuel, ponieważ jest tak samo, ponieważ tankowanie motocykla i samochodu jest takie samo, ale możesz pominąć tę Drive
metodę, ponieważ motocykl jeździ inaczej Car
.
Dzięki dziedziczeniu niektóre klasy są już w pełni zaimplementowane, a inne mają metody, które musisz przesłonić. Z Kompozycją nic ci nie jest dane. (ale możesz zaimplementować interfejsy, wywołując metody w innych klasach, jeśli zdarzy się, że coś wokół ciebie leży).
Kompozycja jest postrzegana jako bardziej elastyczna, ponieważ jeśli masz metodę, taką jak iUsesFuel, możesz mieć metodę gdzieś indziej (inna klasa, inny projekt), która martwi się o radzenie sobie z obiektami, które można zatankować, niezależnie od tego, czy jest to samochód, łódka, piec, grill itp. Interfejsy nakazują, aby klasy, które twierdzą, że implementują ten interfejs, faktycznie miały metody, o które chodzi w tym interfejsie. Na przykład,
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
wtedy możesz mieć metodę gdzie indziej
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
Dziwny przykład, ale pokazuje, że ta metoda nie dba o to, co się wypełnia, ponieważ obiekt implementuje iUsesFuel
, można go wypełnić. Koniec opowieści.
Jeśli zamiast tego użyjesz dziedziczenia, będziesz potrzebować różnych FillHerUp
metod, MotorVehicles
a Barbecues
jeśli nie masz jakiegoś dość dziwnego obiektu podstawowego „ObjectThatUsesFuel”, z którego będziesz mógł dziedziczyć.
ThisCase
, a nie w camelCase
. Dlatego najlepiej nazwać swoje interfejsy IDrivable
itp. Może nie być potrzebne „I”, jeśli poprawnie zgrupujesz wszystkie interfejsy w pakiet.
Czy skład i dziedzictwo są takie same?
Nie są takie same.
Kompozycja : umożliwia traktowanie grupy obiektów w taki sam sposób jak pojedynczej instancji obiektu. Celem kompozytu jest „komponowanie” obiektów w struktury drzewne w celu reprezentowania częściowych hierarchii
Dziedziczenie : klasa dziedziczy pola i metody ze wszystkich swoich nadklas, zarówno bezpośrednich, jak i pośrednich. Podklasa może zastępować odziedziczone metody lub ukrywać dziedziczone pola lub metody.
Jeśli chcę zaimplementować wzorzec kompozycji, jak mogę to zrobić w Javie?
Artykuł w Wikipedii jest wystarczająco dobry, aby zaimplementować wzór złożony w Javie.
Kluczowi uczestnicy:
Komponent :
Liść :
Kompozytowe :
Przykład kodu, aby zrozumieć wzór złożony :
import java.util.List;
import java.util.ArrayList;
interface Part{
public double getPrice();
public String getName();
}
class Engine implements Part{
String name;
double price;
public Engine(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Trunk implements Part{
String name;
double price;
public Trunk(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Body implements Part{
String name;
double price;
public Body(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Car implements Part{
List<Part> parts;
String name;
public Car(String name){
this.name = name;
parts = new ArrayList<Part>();
}
public void addPart(Part part){
parts.add(part);
}
public String getName(){
return name;
}
public String getPartNames(){
StringBuilder sb = new StringBuilder();
for ( Part part: parts){
sb.append(part.getName()).append(" ");
}
return sb.toString();
}
public double getPrice(){
double price = 0;
for ( Part part: parts){
price += part.getPrice();
}
return price;
}
}
public class CompositeDemo{
public static void main(String args[]){
Part engine = new Engine("DiselEngine",15000);
Part trunk = new Trunk("Trunk",10000);
Part body = new Body("Body",12000);
Car car = new Car("Innova");
car.addPart(engine);
car.addPart(trunk);
car.addPart(body);
double price = car.getPrice();
System.out.println("Car name:"+car.getName());
System.out.println("Car parts:"+car.getPartNames());
System.out.println("Car price:"+car.getPrice());
}
}
wynik:
Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0
Wyjaśnienie:
Zobacz poniższe pytanie za i przeciw składowi i dziedziczeniu.
jako kolejny przykład rozważ klasę samochodów, byłoby to dobre wykorzystanie składu, samochód „miałby” silnik, skrzynię biegów, opony, siedzenia itp. Nie rozszerzyłby żadnej z tych klas.
Kompozycja polega na tym, że coś składa się z odrębnych części i ma z nimi silny związek. Jeśli główna część umiera, podobnie jak inni, nie mogą mieć własnego życia. Szorstkim przykładem jest ludzkie ciało. Wyjmij serce, a wszystkie pozostałe części zginą.
Dziedziczenie polega na zabraniu czegoś, co już istnieje, i wykorzystaniu go. Nie ma silnego związku. Człowiek może odziedziczyć majątek ojca, ale może się bez niego obejść.
Nie znam Java, więc nie mogę podać przykładu, ale mogę wyjaśnić pojęcia.
Dziedziczenie między dwiema klasami, gdzie jedna klasa rozszerza inną klasę, ustanawia relację „ JEST A ”.
Kompozycja na drugim końcu zawiera instancję innej klasy w twojej klasie, która ustanawia relację „ Ma A ”. Składanie w java jest przydatne, ponieważ technicznie ułatwia wielokrotne dziedziczenie.
W uproszczeniu agregacja słów oznacza związek ma związek.
Kompozycja jest szczególnym przypadkiem agregacji . W bardziej szczegółowy sposób ograniczona agregacja nazywana jest kompozycją. Jeśli obiekt zawiera drugi obiekt, jeśli zawarty obiekt nie może istnieć bez istnienia obiektu kontenera, wówczas nazywa się to kompozycją. Przykład: klasa zawiera uczniów. Uczeń nie może istnieć bez zajęć. Istnieje kompozycja między klasą a uczniami.
Dlaczego warto korzystać z agregacji
Kod wielokrotnego użytku
Kiedy użyj agregacji
Ponowne użycie kodu można najlepiej osiągnąć poprzez agregację, gdy nie ma statku relacji
Dziedzictwo
Dziedziczenie jest rodzicielskim związkiem dziecięcym. Dziedziczenie oznacza relację
Dziedziczenie w java jest mechanizmem, w którym jeden obiekt nabywa wszystkie właściwości i zachowania obiektu nadrzędnego.
Korzystanie z dziedziczenia w wielokrotnym użyciu kodu Java 1. 2 Dodaj dodatkową funkcję w klasie podrzędnej, a także nadpisywanie metod (aby osiągnąć polimorfizm w czasie wykonywania).
Chociaż zarówno Dziedziczenie, jak i Kompozycja zapewniają możliwość ponownego użycia kodu, główna różnica między Kompozycją a Dziedziczeniem w Javie polega na tym, że Composition umożliwia ponowne użycie kodu bez rozszerzania go, ale w przypadku Dziedziczenia należy rozszerzyć klasę w celu ponownego użycia kodu lub funkcjonalności. Inną różnicą wynikającą z tego faktu jest to, że używając Composition można ponownie użyć kodu nawet dla końcowej klasy, która nie jest rozszerzalna, ale Dziedziczenie nie może ponownie użyć kodu w takich przypadkach. Również za pomocą Composition możesz ponownie użyć kodu z wielu klas, ponieważ są one zadeklarowane jako zmienne składowe, ale dzięki Dziedziczeniu możesz ponownie użyć kodu z jednej klasy, ponieważ w Javie możesz rozszerzyć tylko jedną klasę, ponieważ wielokrotne Dziedziczenie nie jest obsługiwane w Javie . Możesz to zrobić w C ++, ponieważ jedna klasa może rozszerzyć więcej niż jedną klasę. BTW, zawsze powinieneśwolę Kompozycję niż Dziedziczenie w Javie , to nie tylko ja, ale nawet Joshua Bloch zasugerował w swojej książce
Myślę, że ten przykład jasno wyjaśnia różnice między spadkiem a kompozycją .
W tym przykładzie problem został rozwiązany za pomocą dziedziczenia i składu. Autor zwraca uwagę na fakt, że; w dziedziczeniu zmiana nadklasy może powodować problemy w klasie pochodnej, która ją dziedziczy.
Tam możesz również zobaczyć różnicę w reprezentacji, gdy używasz UML do dziedziczenia lub kompozycji.
Dziedziczenie a skład.
Zarówno dziedzictwo, jak i kompozycja są wykorzystywane do ponownego wykorzystania i rozszerzenia zachowania klasowego.
Dziedziczenia stosowane głównie w modelu programowania algorytmów rodzinnych, takim jak typ relacji IS-A, oznacza podobny rodzaj obiektu. Przykład.
Należą one do rodziny samochodów.
Kompozycja reprezentuje typ relacji HAS-A. Pokazuje zdolność obiektu, takiego jak Duster ma pięć przekładni, Safari ma cztery przekładnie itp. Ilekroć musimy rozszerzyć zdolność istniejącej klasy, użyj kompozycji. Przykład: musimy dodać jeszcze jeden sprzęt do obiektu Duster, a następnie musimy utworzyć jeszcze jeden obiekt Gear i skomponować go do obiektu Duster.
Nie powinniśmy wprowadzać zmian w klasie bazowej, dopóki wszystkie klasy pochodne nie będą potrzebować tej funkcjonalności. W tym scenariuszu powinniśmy użyć Composition.Such
klasa A Pochodzi z klasy B
Klasa A Pochodzi z klasy C.
Klasa A Pochodzi z klasy D.
Gdy dodamy dowolną funkcjonalność w klasie A, będzie ona dostępna dla wszystkich podklas, nawet jeśli klasy C i D nie wymagają tej funkcjonalności. W tym scenariuszu musimy utworzyć osobną klasę dla tych funkcji i skomponować ją do wymaganej klasy ( tutaj jest klasa B).
Poniżej znajduje się przykład:
// This is a base class
public abstract class Car
{
//Define prototype
public abstract void color();
public void Gear() {
Console.WriteLine("Car has a four Gear");
}
}
// Here is the use of inheritence
// This Desire class have four gears.
// But we need to add one more gear that is Neutral gear.
public class Desire : Car
{
Neutral obj = null;
public Desire()
{
// Here we are incorporating neutral gear(It is the use of composition).
// Now this class would have five gear.
obj = new Neutral();
obj.NeutralGear();
}
public override void color()
{
Console.WriteLine("This is a white color car");
}
}
// This Safari class have four gears and it is not required the neutral
// gear and hence we don't need to compose here.
public class Safari :Car{
public Safari()
{ }
public override void color()
{
Console.WriteLine("This is a red color car");
}
}
// This class represents the neutral gear and it would be used as a composition.
public class Neutral {
public void NeutralGear() {
Console.WriteLine("This is a Neutral Gear");
}
}
Kompozycja oznacza utworzenie obiektu dla klasy, która ma związek z tą konkretną klasą. Załóżmy, że uczeń ma związek z kontami;
Dziedziczeniem jest, to jest poprzednia klasa z rozszerzoną funkcją. Oznacza to, że ta nowa klasa jest klasą starą z pewnymi rozszerzonymi funkcjami. Załóżmy, że uczeń jest uczniem, ale wszyscy uczniowie są ludźmi. Więc istnieje związek ze studentem i człowiekiem. To jest dziedziczenie.
Nie, oba są różne. Kompozycja podąża za relacją „HAS-A”, a dziedzictwo podąża za relacją „IS-A”. Najlepszym przykładem kompozycji był wzór strategiczny.
Dziedziczenie oznacza ponowne wykorzystanie pełnej funkcjonalności klasy. Tutaj moja klasa musi korzystać ze wszystkich metod superklasy, a moja klasa będzie dosłownie sprzężona z superklasą, a kod zostanie zduplikowany w obu klasach w przypadku dziedziczenia.
Ale możemy rozwiązać ten problem, używając kompozycji do rozmowy z inną klasą. Skład deklaruje atrybut innej klasy w mojej klasie, z którą chcemy porozmawiać. i jakiej funkcjonalności chcemy od tej klasy możemy uzyskać za pomocą tego atrybutu.