Немного странно, но приятно. Я использую String, а не BigDecimal
def round(x: Double)(p: Int): Double = {
var A = x.toString().split('.')
(A(0) + "." + A(1).substring(0, if (p > A(1).length()) A(1).length() else p)).toDouble
}
Они совершенно разные. Наследование - это отношение "is-a" . Композиция представляет собой «has-a» .
Вы выполняете композицию, имея экземпляр другого класса C
в качестве поля вашего класса, вместо расширения C
. Хорошим примером, где состав был бы намного лучше, чем наследование, является java.util.Stack
, который в настоящее время распространяется java.util.Vector
. Это сейчас считается ошибкой. Стек "- это-НЕ-a" вектор; вам не разрешается вставлять и удалять элементы произвольно. Это должно было быть композиция.
К сожалению, слишком поздно исправить эту ошибку дизайна, так как изменение иерархии наследования теперь нарушит совместимость с существующим кодом. Если вместо наследования использовалась композиция 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.
}
в качестве другого примера, рассмотрим класс автомобилей, это будет хорошим использованием композиции, автомобиль будет иметь «двигатель», коробку передач, шины, сиденья и т. д. Он не будет распространять ни один из этих классов.
Являются ли композиция и наследование одинаковыми?
Они не совпадают.
Композиция : позволяет группе объектов обрабатываться так же, как один экземпляр объекта. Цель композита состоит в том, чтобы «компоновать» объекты в древовидных структурах представлять целые иерархии
Inheritance : класс наследует поля и методы из все его суперклассы, прямые или косвенные. Подкласс может переопределять методы, которые он наследует, или он может скрыть поля или методы, которые он наследует.
Если я хочу реализовать шаблон композиции, как я могу это сделать на Java?
Статья в Википедии достаточно хороша для реализации составного шаблона в java.
Ключевые участники:
Компонент:
- Является абстракцией для всех компонентов, включая составные
- Объявляет интерфейс для объектов в композиция
Лист:
- Представляет листовые объекты в композиции
- Реализует все методы Component
Композит:
- Представляет составной компонент (компонент с дочерними элементами)
- Реализует методы манипулирования детьми
- Реализует все методы Component, обычно делегируя их своим детям
Пример кода для понимания Composite patter n:
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
Объяснение:
- Часть - это лист
- Автомобиль содержит много частей
- В автомобиль добавлены запчасти автомобиля
- Цена Автомобиль = сумма (Цена каждой партии)
См. ниже вопрос о преимуществах и недостатках композиции и наследования.
Композиция точно так же звучит - вы создаете объект, вставляя части.
ИЗМЕНИТЬ, что остальная часть этого ответа ошибочно основана на следующем посылке. Это достигается с помощью интерфейсов. Например, используя вышеприведенный пример Car
,
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
Итак, с помощью нескольких стандартных теоретических компонентов вы можете создать свой объект. Это ваша работа, чтобы заполнить, как House
защищает своих обитателей и как Car
защищает своих обитателей.
Наследование походит на все наоборот. Вы начинаете с полного (или полуполного) объекта, и вы заменяете или переопределяете различные биты, которые хотите изменить.
Например, MotorVehicle
может поставляться с методом Fuelable
и Drive
метод. Вы можете оставить метод Fuel так, как он есть, потому что это то же самое, что и заполнять мотоцикл и автомобиль, но вы можете переопределить метод Drive
, потому что Motorbike очень сильно отличается от 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». если вы правильно перегруппируете все свои интерфейсы в пакет.
– ThePyroEagle
21 December 2015 в 11:15
Наследование выявляет отношение IS-A. Композиция выявляет связь HAS-A. Шаблон Statergy объясняет, что композиция должна использоваться в тех случаях, когда существуют семейства алгоритмов, определяющих конкретное поведение. Классический пример - тип утки, который реализует поведение мух.
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");
}
}
Если бы для наследования у нас было бы два разных класса птиц, которые снова и снова реализуют функцию мух. Это наследование и состав совершенно разные.
Композиция означает создание объекта для класса, который имеет отношение к этому конкретному классу. Предположим, что у Студента есть связь с Учётами;
Наследование - это предыдущий класс с расширенной функцией. Это означает, что этот новый класс - это класс Old с некоторой расширенной функцией. Предположим, что студент - студент, но все ученики - это люди. Так что есть отношения со студентами и людьми. Это Наследование.
В «Агрегации простого слова» означает «Отношения».
Состав - это особый случай агрегации. Более конкретно, ограниченная агрегация называется композицией. Когда объект содержит другой объект, если содержащийся объект не может существовать без существования контейнерного объекта, тогда он называется композицией. Пример: класс содержит студентов. Студент не может существовать без класса. Существует композиция между классом и учениками.
Зачем использовать Aggregation
Повторное использование кода
Когда использование агрегирования
Повторное использование кода также наилучшим образом достигается путем агрегирования, когда нет Относительный корабль
Наследование
Наследование является родительским отношением к дочерним отношениям, связанным с отношением. RelationShip
Наследование в Java - это механизм, в котором один объект приобретает все свойства и поведение родительского объекта.
Использование наследования в Java 1 Повторное использование кода. 2 Добавить дополнительную функцию в дочернем классе, а также переопределение метода (поэтому может быть достигнут полиморфизм выполнения).
Хотя оба наследования и композиции обеспечивают повторное использование кода, основное различие между композицией и наследованием в Java заключается в том, что Composition позволяет повторно использовать код без его расширения, но для Inheritance вы должны расширить класс для повторного использования кода или функциональности. Другое отличие от этого факта заключается в том, что с помощью композиции вы можете повторно использовать код для даже окончательного класса, который не является расширяемым, но Inheritance не может повторно использовать код в таких случаях. Кроме того, используя Composition, вы можете повторно использовать код из многих классов, поскольку они объявлены как только переменная-член, но с Inheritance вы можете повторно использовать форму кода только одного класса, потому что в Java вы можете расширять только один класс, поскольку множественное Наследование не поддерживается в Java , Вы можете сделать это на C ++, хотя из-за того, что один класс может расширять несколько классов. Кстати, вы всегда должны предпочитать композицию над наследованием в Java, ее не только я, но даже Джошуа Блох предложил в своей книге
Как наследование может быть опасным?
Давайте возьмем пример
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 несовместимым. Так что такая зависимость может подниматься до любого уровня, и это может быть опасно. Каждый раз, когда суперкласс может не иметь полной видимости для кода внутри всех его подклассов, и подкласс может постоянно замечать, что происходит в suerclass все время. Поэтому мы должны избегать этой сильной и ненужной связи.
Как композиция решает эту проблему?
Давайте посмотрим, пересматривая тот же пример
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 reference Я могу вызывать методы класса X, а также класс Y. Эта гибкость никогда не существовала в наследовании
3) Еще одно большое преимущество: Unit testing
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». Лучшим примером для композиции был стратегический паттерн.
Я думаю, что этот пример ясно объясняет различия между наследованием и композицией.
В этом случае проблема решена с использованием наследования и композиции. Автор обращает внимание на то, что; в наследовании изменение в суперклассе может вызвать проблемы в производном классе, которые наследуют его.
Там вы также можете увидеть разницу в представлении, когда используете UML для наследования или композиции.
Состав состоит из того, что что-то состоит из отдельных частей и имеет прочные отношения с этими частями. Если основная часть умирает, так и другие, у них не может быть собственной жизни. Грубым примером является человеческое тело. Выньте сердце, и все остальные части отмирают.
Наследование - это то, где вы просто берете то, что уже существует и использует его. Нет сильных отношений. Человек мог наследовать свое отцовское имение, но он может обойтись без него.
Я не знаю Java, поэтому я не могу представить пример, но я могу дать объяснение понятий.
Наследование Vs Состав.
Наследования и состав используются для повторного использования и расширения поведения класса.
Наследование в основном используется в модели программирования алгоритмов семейства, такой как тип отношения IS-A, означает аналогичный объект. Пример.
. Они принадлежат семейству Car.
Композиция представляет собой отношение HAS-A Type.It показывает способность объекта, такого как Duster, иметь Five Gears, Safari имеет четыре Gears и т. д. Всякий раз, когда нам нужно расширить способность существующего класса, используйте композицию. Например, нам нужно добавить еще одна передача в объекте Duster, тогда мы должны создать еще один объект передачи и скомпоновать его объекту duster.
Мы не должны вносить изменения в базовый класс до тех пор, пока все производные классы не нуждаются в этих функциях. Для этого сценария мы должны использовать Composition.Such как
класс A Производится классом B
Класс A Производится классом C
Класс A Производится классом D.
Когда мы добавляем какие-либо функциональные возможности в класс А, тогда он доступен для всех подклассов, даже если классам 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");
}
}
Inheritence означает повторное использование полной функциональности класса. Здесь мой класс должен использовать все методы суперкласса, и мой класс будет связан с суперклассом, и код будет дублироваться в обоих классах в случае наследования .
Но мы можем преодолеть все эти проблемы, когда мы используем композицию для общения с другим классом. композиция объявляет атрибут другого класса в мой класс, о котором мы хотим поговорить. и какую функциональность мы хотим от этого класса, которую мы можем получить, используя этот атрибут.