Content deleted Content added
Removed Python because the stackoverflow answers references are bullshit. One is an awful hack at best. The other is only for a single internal class, not for more than one. Python has no mitigation for the problem stated. OTOH it has no problem with diamond inheritance. |
m →Avoiding drawbacks: General fixes via AutoWikiBrowser |
||
(18 intermediate revisions by 15 users not shown) | |||
Line 1:
{{Short description|Software design pattern}}
[[File:UML diagram of composition over inheritance.svg|thumb|right|444px|This diagram shows how the fly and sound behavior of an animal can be designed in a flexible way by using the composition over inheritance design principle.<ref name="FHDPs" />]]
'''Composition over inheritance''' (or '''composite reuse principle''') in [[object-oriented programming]] (OOP) is the principle that classes should
| url = https://books.google.com/books?id=4pjbgVHzomsC&q=composite+reuse+principle&pg=PA17
| title = Java Design - Objects, UML, and Process: 1.1.5 Composite Reuse Principle (CRP)
Line 12 ⟶ 10:
| isbn = 9780201750447
| accessdate = 2012-05-29
}}</ref>
</ref>
==Basics==
An implementation of composition over inheritance typically begins with the creation of various [[Interface (computing)#In object-oriented languages|interfaces]] representing the behaviors that the system must exhibit. Interfaces can facilitate [[Polymorphism (computer science)|polymorphic]] behavior. Classes implementing the identified interfaces are built and added to
In fact, business ___domain classes may all be base classes without any inheritance at all. Alternative implementation of system behaviors is accomplished by providing another class that implements the desired behavior interface. A class that contains a reference to an interface can support implementations of the interface—a choice that can be delayed until [[Runtime (program lifecycle phase)|runtime]].
Line 78 ⟶ 76:
===Composition and interfaces===
The C++ examples in this section demonstrate the principle of using composition and interfaces to achieve code reuse and polymorphism. Due to the C++ language not having a dedicated keyword to declare interfaces, the following C++ example uses inheritance from a pure [[abstract base class]]. For most purposes, this is functionally equivalent to the interfaces provided in other languages, such as Java<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|87}} and C#.<ref name=Price>{{cite book |last=Price | first=Mark J. |title=C# 8.0 and .NET Core 3.0 – Modern Cross-Platform Development: Build Applications with C#, .NET Core, Entity Framework Core, ASP.NET Core, and ML.NET Using Visual Studio Code | date=2022 | publisher= Packt |isbn= 978-1-098-12195-2}}</ref>{{rp|144}}
Introduce an abstract class named {{code|VisibilityDelegate}}, with the subclasses {{code|NotVisible}} and {{code|Visible}}, which provides a means of drawing an object:
Line 213 ⟶ 211:
==Benefits==
To favor composition over inheritance is a design principle that gives the design higher flexibility. It is more natural to build business-___domain classes out of various components than trying to find commonality between them and creating a family tree. For example, an accelerator pedal and a steering wheel share very few common [[Trait (computer programming)|traits]], yet both are vital components in a car. What they can do and how they can be used to benefit the car
| last1 = Freeman
| first1 = Eric
Line 240 ⟶ 238:
For example, in the C# code below, the variables and methods of the {{code|Employee}} base class are inherited by the {{code|HourlyEmployee}} and {{code|SalariedEmployee}} derived subclasses. Only the {{code|Pay()}} method needs to be implemented (specialized) by each derived subclass. The other methods are implemented by the base class itself, and are shared by all of its derived subclasses; they do not need to be re-implemented (overridden) or even mentioned in the subclass definitions.
[[File:UML class Employee.svg|UML class Employee.svg]]
<syntaxhighlight lang="csharp">
Line 283:
Some languages provide specific means to mitigate this:
* [[C Sharp (programming language)|C#]] provides default interface methods since version 8.0 which allows to define body to interface member.<ref>{{cite web | url=https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#default-interface-methods | title=What's new in C# 8.0 | website=Microsoft Docs | publisher=Microsoft | access-date=2019-02-20}}</ref><ref name=Price/>{{rp|28–29}}<ref name=Skeet>{{cite book |last=Skeet|first=Jon|title= C# in Depth |date=23 March 2019 |publisher= Manning |isbn= 978-1617294532}}</ref>{{rp|38}}<ref name=Albahari>{{cite book |last=Albahari |first=Joseph |title= C# 10 in a Nutshell |date=2022 |publisher= O'Reilly |isbn= 978-1-098-12195-2}}</ref>{{rp|466–468}}
* [[D (programming language)|D]] provides an explicit "alias this" declaration within a type can forward into it every method and member of another contained type.<ref>{{cite web | url=https://dlang.org/spec/class.html#alias-this | title=Alias This | website=D Language Reference| access-date=2019-06-15}}</ref>
* [[Dart (programming language)|Dart]] provides mixins with default implementations that can be shared.
* [[Go (programming language)|Go]] type embedding avoids the need for forwarding methods.<ref>{{cite web | url=https://golang.org/doc/effective_go.html#embedding | title=''(Type)'' Embedding | website=The Go Programming Language Documentation | access-date=2019-05-10}}</ref>
* [[Java (programming language)|Java]] provides default interface methods since version 8.<ref name=Bloch/>{{rp|104}} Project Lombok<ref>https://projectlombok.org {{Bare URL inline|date=August 2024}}</ref> supports delegation using the {{code|@Delegate}} annotation on the field, instead of copying and maintaining the names and types of all the methods from the delegated field.<ref>{{cite web | url=https://projectlombok.org/features/experimental/Delegate | title=@Delegate | website=Project Lombok | access-date=2018-07-11}}</ref>
* [[Julia (programming language)|Julia]] macros can be used to generate forwarding methods. Several implementations exist such as Lazy.jl<ref>{{cite web | url=https://github.com/MikeInnes/Lazy.jl | title=MikeInnes/Lazy.jl | website=[[GitHub]] }}</ref> and TypedDelegation.jl.<ref>{{cite web | url=https://github.com/JeffreySarnoff/TypedDelegation.jl | title=JeffreySarnoff/TypedDelegation.jl | website=[[GitHub]] }}</ref><ref>{{cite web |title=Method forwarding macro |url=https://discourse.julialang.org/t/method-forwarding-macro/23355 |website=JuliaLang |access-date=18 August 2022 |language=en |date=20 April 2019}}</ref>
* [[Kotlin (programming language)|Kotlin]] includes the delegation pattern in the language syntax.<ref>{{cite web | url=https://kotlinlang.org/docs/reference/delegated-properties.html | title=Delegated Properties | website=Kotlin Reference | publisher=JetBrains | access-date=2018-07-11}}</ref>
* [[PHP]] supports [[Traits (computer science)|traits]], since PHP 5.4.<ref>{{cite web |title=PHP: Traits |url=https://www.php.net/manual/en/language.oop5.traits.php |website=www.php.net |access-date=23 February 2023}}</ref>
* [[Raku (programming language)|Raku]] provides a {{code|handles}} trait to facilitate method forwarding.<ref>{{cite web |title=Type system |url=https://docs.raku.org/language/typesystem#index-entry-handles_trait-handles |website=docs.raku.org |access-date=18 August 2022}}</ref>
* [[Rust (programming language)|Rust]] provides traits with default implementations.
|