Состав и наследование одинаковы? Если я хочу реализовать шаблон композиции, как я могу сделать это в Java?
Состав и наследование одинаковы? Если я хочу реализовать шаблон композиции, как я могу сделать это в Java?
Ответы:
Они абсолютно разные. Наследование - это отношения "есть" . Композиция "есть" .
Вы создаете композицию, имея экземпляр другого класса C
в качестве поля вашего класса вместо расширения C
. Хороший пример, где состав был бы намного лучше, чем наследование java.util.Stack
, в настоящее время расширяется java.util.Vector
. Это сейчас считается ошибкой. Вектор стека "НЕ-НЕ" ; Вы не должны иметь права вставлять и удалять элементы произвольно. Это должна была быть композиция вместо этого.
К сожалению, уже слишком поздно исправлять эту ошибку проектирования, поскольку изменение иерархии наследования теперь нарушит совместимость с существующим кодом. Если бы Stack
вместо наследования использовалась композиция, ее всегда можно изменить, чтобы использовать другую структуру данных, не нарушая API .
Я очень рекомендую книгу Джоша Блоха Effective Java 2nd Edition
Хороший объектно-ориентированный дизайн не связан с расширением существующих классов. Ваш первый инстинкт должен сочинять вместо этого.
Смотрите также:
Композиция означает 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;
}
В классе Test, используя ссылку 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 , автомобиль « is-a » Fillable и может использоваться в вашем коде везде, где вы используете Fillable .
Композиция принципиально отличается от наследования. Когда вы используете композицию, вы (как отмечается в других ответах) устанавливаете отношение « есть » между двумя объектами, в отличие от отношения « есть », которое вы устанавливаете при использовании наследования .
Итак, из примеров автомобилей в других вопросах, если бы я хотел сказать, что у автомобиля есть «бензобак», я бы использовал композицию следующим образом:
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
методом. Вы можете оставить метод Fuel таким, какой он есть, потому что он одинаков для заправки мотоцикла и автомобиля, но вы можете переопределить Drive
метод, потому что мотоцикл движется совсем иначе, чем a Car
.
С наследованием некоторые классы уже полностью реализованы, а у других есть методы, которые вы вынуждены переопределить. С Композицией вам ничего не дано. (но вы можете реализовать интерфейсы, вызывая методы в других классах, если у вас что-то есть).
Композиция выглядит более гибкой, потому что если у вас есть метод, такой как iUsesFuel, у вас может быть метод где-то еще (другой класс, другой проект), который просто заботится о работе с объектами, которые можно заправлять, независимо от того, является ли это автомобилем, лодка, печь, барбекю и т. д. Интерфейсы требуют, чтобы классы, которые говорят, что они реализуют этот интерфейс, на самом деле имеют методы, о которых этот интерфейс - все. Например,
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
тогда вы можете иметь метод где-то еще
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
Странный пример, но он показывает, что этот метод не заботится о том, что он заполняет, потому что объект реализует iUsesFuel
, он может быть заполнен. Конец истории.
Если бы вместо этого вы использовали Inheritance, вам потребовались бы другие FillHerUp
методы, MotorVehicles
и Barbecues
если у вас не было достаточно странного базового объекта «ObjectThatUsesFuel» для наследования.
ThisCase
, а не в camelCase
. Поэтому лучше называть свои интерфейсы IDrivable
и т. Д. Вам может не понадобиться «I», если вы правильно перегруппировали все свои интерфейсы в пакет.
Состав и наследование одинаковы?
Они не одинаковы.
Композиция : она позволяет обрабатывать группу объектов так же, как отдельный экземпляр объекта. Назначение составной части состоит в том, чтобы «объединять» объекты в древовидные структуры для представления иерархий части-целого
Наследование : класс наследует поля и методы от всех своих суперклассов, прямых или косвенных. Подкласс может переопределять методы, которые он наследует, или он может скрывать поля или методы, которые он наследует.
Если я хочу реализовать шаблон композиции, как я могу сделать это в 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 Code Reusability. 2 Добавьте дополнительную функцию в дочерний класс, а также переопределение метода (чтобы можно было достичь полиморфизма во время выполнения).
Хотя и Наследование, и Композиция обеспечивают возможность повторного использования кода, основное отличие Композиции от Наследования в Java заключается в том, что Композиция позволяет повторно использовать код без его расширения, но для Наследования вы должны расширить класс для любого повторного использования кода или функциональности. Другое отличие, вытекающее из этого факта, состоит в том, что с помощью Composition вы можете повторно использовать код даже для конечного класса, который не является расширяемым, но Inheritance не может повторно использовать код в таких случаях. Также с помощью Composition вы можете повторно использовать код из многих классов, поскольку они объявлены как просто переменные-члены, но с помощью Inheritance вы можете повторно использовать код только для одного класса, потому что в Java вы можете расширить только один класс, потому что множественное наследование не поддерживается в Java , Вы можете сделать это в C ++, потому что один класс может расширять несколько классов. Кстати, вы должны всегдаЯ предпочитаю композицию наследованию в Java , это не только я, но даже Джошуа Блох предложил в своей книге
Я думаю, что этот пример ясно объясняет различия между наследованием и составом .
В этом примере проблема решается с использованием наследования и композиции. Автор обращает внимание на то, что; в наследовании изменение в суперклассе может вызвать проблемы в производном классе, которые наследуют его.
Там вы также можете увидеть разницу в представлении, когда вы используете UML для наследования или композиции.
Наследование против композиции.
Наследование и композиция используются для повторного использования и расширения поведения класса.
Наследование в основном используется в модели программирования семейного алгоритма, такой как тип отношения IS-A, означает похожий тип объекта. Пример.
Они принадлежат семье автомобилей.
Композиция представляет тип отношения HAS-A. Она показывает способность объекта, такого как Duster, имеет пять Gears, Safari имеет четыре Gears и т. Д. Когда нам нужно расширить возможности существующего класса, используйте композицию. Например, нам нужно добавить еще одну шестеренку в объект Duster, затем мы должны создать еще один объект шестеренки и скомпоновать ее с объектом Duster.
Мы не должны вносить изменения в базовый класс до тех пор, пока / если все производные классы не нуждаются в этих функциях. Для этого сценария мы должны использовать Composition.Such как
класс A, полученный классом B
Класс A, полученный классом C
Класс A Производный от класса D.
Когда мы добавляем какую-либо функциональность в класс A, она становится доступной для всех подклассов, даже если классы C и D не требуют этих функциональных возможностей. Для этого сценария нам нужно создать отдельный класс для этих функциональных возможностей и объединить его с требуемым классом ( здесь класс B).
Ниже приведен пример:
// 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". Лучшим примером для композиции был стратегический шаблон.
Наследование означает повторное использование всей функциональности класса. Здесь мой класс должен использовать все методы суперкласса, и мой класс будет аккуратно связан с суперклассом, и код будет продублирован в обоих классах в случае наследования.
Но мы можем преодолеть все эти проблемы, когда используем композицию для общения с другим классом. Композиция объявляет атрибут другого класса в моем классе, с которым мы хотим поговорить. и какую функциональность мы хотим от этого класса мы можем получить с помощью этого атрибута.