Чи однаковий склад і спадщина? Якщо я хочу реалізувати шаблон композиції, як це зробити на Java?
Чи однаковий склад і спадщина? Якщо я хочу реалізувати шаблон композиції, як це зробити на Java?
Відповіді:
Вони абсолютно різні. Спадщина - це "є-а" відносини. Склад - це «є-є» .
Ви створюєте композицію, маючи екземпляр іншого класу C
як поле свого класу, а не розширюючи C
. Хороший приклад, коли склад був би набагато кращим за спадщину java.util.Stack
, який зараз поширюється java.util.Vector
. Зараз це вважається помилкою. Стек "є-НЕ-а" вектор; вам не можна дозволяти вставляти та видаляти елементи довільно. Натомість це мала бути композиція.
На жаль, пізно виправити цю помилку дизайну, оскільки зміна ієрархії спадкування тепер порушить сумісність із існуючим кодом. Якщо Stack
використовується композиція замість успадкування, її завжди можна модифікувати для використання іншої структури даних без порушення API .
Я настійно рекомендую книгу Джоша Блоха « Ефективна Java 2-го видання»
Хороший об’єктно-орієнтований дизайн не полягає в тому, щоб розширити існуючі класи. Першим вашим інстинктом має бути складання замість цього.
Дивитися також:
Склад означає HAS A
Спадкові засобиIS A
Example
: У автомобіля є двигун, а автомобіль - автомобіль
У програмуванні це представлено як:
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
поле типуEnum
Наскільки спадщина може бути небезпечною?
Давайте візьмемо приклад
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1) Як зрозуміло у наведеному вище коді, клас Y має дуже сильну зв'язок з класом X. Якщо щось зміниться в суперкласі X, Y може різко зламатись. Припустимо, у майбутньому класі X реалізується робота з методом із підписом нижче
public int work(){
}
Зміна проводиться в класі X, але це зробить клас Y невідмінним. Тож така залежність може піднятися на будь-який рівень, і це може бути дуже небезпечно. Кожен раз, коли суперклас може не мати повної видимості для кодування у всіх його підкласах і підкласах, можна постійно помічати, що відбувається в надкласі. Тому нам потрібно уникати цієї сильної і непотрібної зв'язку.
Як композиція вирішує це питання?
Подивимось, переглянувши той же приклад
public class X{
public void do(){
}
}
Public Class Y{
X x = new X();
public void work(){
x.do();
}
}
Тут ми створюємо посилання на X клас у Y класі та викликаємо метод X класу, створюючи екземпляр X класу. Тепер уся ця сильна муфта пропала. Суперклас та підклас зараз сильно незалежні один від одного. Заняття можуть вільно вносити зміни, які були небезпечними для спадкової ситуації.
2) Друга дуже добра перевага композиції в тому, що вона забезпечує метод, що викликає гнучкість, наприклад:
class X implements R
{}
class Y implements R
{}
public class Test{
R r;
}
У тестовому класі, використовуючи посилання r, я можу викликати методи X класу, а також класу Y. Ця гнучкість ніколи не була у спадок
3) Ще одна велика перевага: модульне тестування
public class X {
public void do(){
}
}
Public Class Y {
X x = new X();
public void work(){
x.do();
}
}
У наведеному вище прикладі, якщо стан екземпляра x невідомий, його можна легко виправити за допомогою деяких тестових даних, і всі методи можуть бути легко перевірені. Це взагалі було неможливо у спадок, оскільки ви сильно залежали від суперкласу, щоб отримати стан екземпляра та виконати будь-який метод.
4) Ще однією вагомою причиною, чому нам слід уникати спадкування, є те, що Java не підтримує багаторазове успадкування.
Давайте візьмемо приклад, щоб зрозуміти це:
Public class Transaction {
Banking b;
public static void main(String a[])
{
b = new Deposit();
if(b.deposit()){
b = new Credit();
c.credit();
}
}
}
Добре знати :
композиція легко досягається під час виконання, тоді як успадкування надає свої особливості під час компіляції
Склад також відомий як відношення HAS-A, а успадкування також відоме як відношення IS-A
Тому зробіть звичку завжди віддавати перевагу складу над спадщиною з різних вищезазначених причин.
Відповідь, надана @Michael Rodrigues, є невірною (прошу вибачення; я не можу коментувати прямо), і могла призвести до певної плутанини.
Реалізація інтерфейсу - це форма успадкування ... коли ви реалізуєте інтерфейс, ви не тільки успадковуєте всі константи, ви здійснюєте об'єкт такого типу, який визначений інтерфейсом; це все-таки стосунки " є-а ". Якщо автомобіль реалізує Fillable , автомобіль " є-a " Задається , і його можна використовувати у вашому коді, де б ви не використовували Fillable .
Склад принципово відрізняється від спадкового. Коли ви використовуєте композицію, ви (як відзначають інші відповіді) створюєте відносини " has-a " між двома об'єктами, на відміну від відносини " є-а ", яке ви створюєте , коли використовуєте спадщину .
Отже, з прикладів автомобіля в інших питаннях, якби я хотів сказати, що автомобіль має "цистерну" з бензином, я б використав склад таким чином:
public class Car {
private GasTank myCarsGasTank;
}
Сподіваємось, це усуне будь-яке непорозуміння.
Спадщина виявляє відношення IS-A . Композиція виявляє відношення HAS-A . Структура стратегії пояснює, що Композицію слід застосовувати у випадках, коли є сімейства алгоритмів, що визначають певну поведінку.
Класичний приклад - клас качок, який реалізує поведінку літаючих.
public interface Flyable{
public void fly();
}
public class Duck {
Flyable fly;
public Duck(){
fly = new BackwardFlying();
}
}
Таким чином, ми можемо мати кілька класів, які реалізують політ, наприклад:
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");
}
}
Якби це було у спадок, у нас було б два різних класу птахів, які реалізовують функцію мухи знову і знову. Тож успадкування та склад абсолютно різні.
Композиція така, як звучить - ви створюєте об’єкт, підключаючи частини.
Редагуйте решту цієї відповіді помилково, виходячи з наступної передумови.
Це здійснюється за допомогою інтерфейсів.
Наприклад, використовуючи Car
приклад вище,
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
Тож за допомогою декількох стандартних теоретичних компонентів ви можете створити свій об’єкт. Тоді ваша робота заповнити, як House
захищає своїх мешканців, і як Car
захищає своїх мешканців.
Спадщина - це як навпаки. Ви починаєте з повного (або напівповне) об’єкта і замінюєте або переосмислюєте різні біти, які хочете змінити.
Наприклад, MotorVehicle
може бути використаний Fuelable
метод і Drive
метод. Ви можете залишити метод палива таким, яким він є, тому що це те саме, щоб заповнити мотоцикл і автомобіль, але ви можете перекрити Drive
метод, оскільки мотоцикл рухається дуже інакшеCar
.
З успадкуванням деякі класи вже реалізовані повністю, а в інших є методи, які ви змушені перекривати. Зі складу вам нічого не дано. (але ви можете реалізувати інтерфейси, викликаючи методи в інших класах, якщо у вас трапиться щось прокладення).
Склад вважається більш гнучким, тому що якщо у вас є такий метод, як iUsesFuel, ви можете мати метод десь в іншому місці (інший клас, інший проект), який просто хвилює справу з предметами, які можна заправити, незалежно від того, чи це автомобіль, човен, піч, барбекю та ін. Інтерфейси передбачають, що класи, які говорять, що вони реалізують цей інтерфейс, насправді мають методи, якими цей інтерфейс є. Наприклад,
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
тоді ви можете мати метод десь в іншому місці
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
Дивний приклад, але він показує, що цей метод не хвилює, чим він заповнюється, тому що об'єкт реалізує iUsesFuel
, він може бути заповнений. Кінець історії.
Якщо ви використовували Наслідування, вам знадобляться різні FillHerUp
методи боротьби MotorVehicles
і Barbecues
, якщо у вас не був якийсь досить дивний базовий об'єкт "ObjectThatUsesFuel", від якого слід успадкувати.
ThisCase
, а не в camelCase
. Тому найкраще називати свої інтерфейси IDrivable
тощо. Можливо, вам не знадобиться "Я", якщо ви перегрупуєте всі свої інтерфейси в пакет правильно.
Чи однаковий склад і спадщина?
Вони не однакові.
Склад : Це дає змогу групі об'єктів поводитися так само, як і окремий екземпляр об'єкта. Метою композиту є "складання" об'єктів у структурах дерев, щоб представити ієрархії частини цілого
Спадщина : клас успадковує поля та методи від усіх своїх суперклассів, прямих чи непрямих. Підклас може змінювати методи, які він успадковує, або може приховати поля чи методи, які він успадковує.
Якщо я хочу реалізувати шаблон композиції, як це зробити на Java?
Стаття у Вікіпедії досить хороша, щоб реалізувати композитний малюнок у Java.
Основні учасники:
Компонент :
Лист :
Композит :
Приклад коду для розуміння складеного шаблону:
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());
}
}
вихід:
Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0
Пояснення:
До плюсів і мінусів складу та успадкування див. Нижче питання.
як інший приклад, розглянемо клас автомобілів, це було б добре використовувати склад, автомобіль "мав би" двигун, коробку передач, шини, сидіння тощо. Це не поширювало б жоден із цих класів.
Композиція - це те, де щось складається з різних частин, і воно має тісний зв’язок з цими частинами. Якщо основна частина помирає так, як і інші, вони не можуть мати власне життя. Грубий приклад - людський організм. Вийняти серце, і всі інші частини відмирають.
Спадщина - це те, коли ти просто береш щось, що вже існує, і використовуєш його. Сильних стосунків немає. Людина могла успадкувати майно своїх батьків, але він може обійтися і без цього.
Я не знаю Java, тому не можу навести приклад, але можу надати пояснення понять.
Спадкування між двома класами, коли один клас поширює інший клас встановлює " IS A ".
Композиція на іншому кінці містить екземпляр іншого класу у вашому класі, встановлює відносини " Має А ". Композиція в java корисна, оскільки технічно полегшує багаторазове успадкування.
У простому слові агрегації означає, що має стосунки ..
Склад - особливий випадок агрегації . Більш конкретним способом обмежена агрегація називається композицією. Якщо об'єкт містить інший об'єкт, якщо об'єкт, що міститься, не може існувати без існування об'єкта контейнера, він називається складом. Приклад: Клас містить учнів. Студент не може існувати без класу. Існує склад між класом і студентами.
Навіщо використовувати агрегацію
Використання коду
При використанні агрегації
Повторне використання коду також найкраще досягається шляхом агрегування, коли немає відношення
Спадщина
Спадщина - це стосунки батьківських батьків. Значення спадщини - це відносини
Спадщина в java - це механізм, за допомогою якого один об'єкт набуває всіх властивостей і поведінки материнського об'єкта.
Використання успадкування в Java 1 Код повторної використання. 2 Додайте додаткову особливість у дитячому класі, а також переосмислення методу (так можна досягти поліморфізму виконання).
Хоча і Inheritance, і Composition надають можливість повторної використання коду, головна відмінність Composition від Inheritance у Java полягає в тому, що Composition дозволяє повторно використовувати код, не розширюючи його, але для Inheritance ви повинні розширити клас для будь-якого повторного використання коду чи функціональності. Ще одна відмінність, що випливає з цього факту, полягає в тому, що за допомогою композиції ви можете повторно використовувати код навіть для остаточного класу, який не розширюється, але Спадщина не може повторно використовувати код у таких випадках. Також за допомогою композиції ви можете повторно використовувати код з багатьох класів, оскільки вони оголошені просто змінною члена, але за допомогою Inheritance ви можете повторно використовувати кодову форму лише одного класу, тому що в Java ви можете розширити лише один клас, тому що множинне спадкування не підтримується в Java . Це можна зробити в C ++, хоча там один клас може поширювати більше одного класу. До речі, завжди слідвіддайте перевагу композиції над спадщиною на Java , її не тільки я, але навіть Джошуа Блох запропонував у своїй книзі
Я думаю, що цей приклад чітко пояснює різницю між спадщиною та складом .
У цьому прикладі проблема вирішується за допомогою успадкування та складу. Автор звертає увагу на те, що; в успадкуванні зміна суперкласу може спричинити проблеми у похідному класі, які успадковують його.
Там ви також можете побачити різницю в представленні, коли ви використовуєте UML для успадкування або складу.
Спадкові Vs Склад.
Спадковість і склад використовуються для повторної використання та розширення поведінки класу.
Спадки в основному використовують в моделі програмування сімейного алгоритму, такі як тип відношення IS-A означає об'єкт подібного типу. Приклад.
Ці належать до родини автомобілів.
Склад являє собою тип відносин HAS-A. Він показує здатність такого об'єкта, як Duster має п'ять передач, Safari чотири Gears і т.д. Приклад: нам потрібно додати ще одну передачу в об'єкт Duster, тоді ми повинні створити ще один редуктор і скласти його до об'єкта пилу.
Ми не повинні вносити зміни до базового класу до тих пір, поки всі похідні класи не потребують цієї функціональності. Для цього сценарію ми повинні використовувати Composition.Such as
клас А Похідне класом В
Клас А Похідний класом С
Клас A Похідний класом D.
Коли ми додаємо будь-яку функціональність до класу A, він доступний для всіх підкласів, навіть коли для класів C і D ці функції не потребують. Для цього сценарію нам потрібно створити окремий клас для цих функціональних можливостей і скласти його до необхідного класу ( ось клас В).
Нижче наведено приклад:
// 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");
}
}
Композиція означає створення об'єкта для класу, який має відношення до цього конкретного класу. Припустимо, студент має відношення до облікових записів;
Спадщина - це попередній клас із розширеною функцією. Це означає, що цей новий клас - це Старий клас з деякою розширеною особливістю. Припустимо, студент - студент, але всі студенти - люди. Отже, існує зв’язок зі студентом і людиною. Це наслідування.
Ні, обидва різні. Склад дотримується відносин "HAS-A", а спадкування - "IS-A". Найкращим прикладом для композиції був Стратегічний зразок.
Спадщина означає повторне використання повної функціональності класу. Тут мій клас повинен використовувати всі методи суперкласу, і мій клас буде тісно поєднаний із суперкласом, і код буде дублюватися в обох класах у разі спадкування.
Але ми можемо подолати всі ці проблеми, коли використовуємо композицію для розмови з іншим класом. композиція оголошує атрибут іншого класу в моєму класі, з яким ми хочемо поговорити. і яку функціональність ми хочемо отримати від цього класу, використовуючи цей атрибут.