SlideShare a Scribd company logo
1 of 15
Download to read offline
Favor composition over
inheritance
1
Why favor composition over inheritance?
• Inheritance is often overused; composition is a better alternative in
many cases
• Inheritance can make your code fragile
• Inheritance is inflexible
2
Inheritance can make your code
fragile
3
Example: piece of code used by a cafe
interface Beverage {
BigDecimal price();
String description();
}
class Order {
private static final BigDecimal TAX_RATE = new BigDecimal("0.1");
private BigDecimal subTotal = BigDecimal.ZERO;
void add(Beverage beverage) {
subTotal = subTotal.add(beverage.price());
}
void addAll(Collection<? extends Beverage> beverages) {
for (Beverage beverage : beverages)
subTotal = subTotal.add(beverage.price());
}
BigDecimal grandTotal() {
BigDecimal tax = subTotal.multiply(TAX_RATE);
return subTotal.add(tax);
}
}
4
New requirement: discount campaign
class CampaignOrder extends Order {
private static final BigDecimal DISCOUNT_RATE = new BigDecimal("0.2");
private int numberOfBeverages;
@Override void add(Beverage beverage) {
super.add(beverage);
numberOfBeverages++;
}
@Override void addAll(Collection<? extends Beverage> beverages) {
super.addAll(beverages);
numberOfBeverages += beverages.size();
}
@Override BigDecimal grandTotal() {
BigDecimal grandTotal = super.grandTotal();
if (numberOfBeverages > 2) {
BigDecimal discount = grandTotal.multiply(DISCOUNT_RATE);
grandTotal = grandTotal.subtract(discount);
}
return grandTotal;
}
}
5
Refactoring of Order can break CampaignOrder
class Order {
...
void add(Beverage beverage) {
subTotal = subTotal.add(beverage.price());
}
void addAll(Collection<? extends Beverage> beverages) {
for (Beverage beverage : beverages)
// Someone has done refactoring here:
// subTotal = subTotal.add(beverage.price());
add(beverage);
}
...
}
• This refactoring has broken CampaignOrder;
now CampaignOrder#numberOfBeverages gets incremented twice for every addAll() call
• The problem: CampaignOrder relies on an implementation detail of its super class
• Using inheritance this way should be avoided because that introduces fragility to the codebase
6
Better approach: composition (1/2)
interface Order {
void add(Beverage beverage);
void addAll(Collection<? extends Beverage> beverages);
BigDecimal grandTotal();
}
class RegularOrder implements Order {
private static final BigDecimal TAX_RATE = new BigDecimal("0.1");
private BigDecimal subTotal = BigDecimal.ZERO;
@Override public void add(Beverage beverage) {
subTotal = subTotal.add(beverage.price());
}
@Override public void addAll(Collection<? extends Beverage> beverages) {
for (Beverage beverage : beverages)
subTotal = subTotal.add(beverage.price());
}
@Override public BigDecimal grandTotal() {
BigDecimal tax = subTotal.multiply(TAX_RATE);
return subTotal.add(tax);
}
}
7
Better approach: composition (2/2)
class CampaignOrder implements Order {
private static final BigDecimal DISCOUNT_RATE = new BigDecimal("0.2");
private int numberOfBeverages;
private final Order delegate;
CampaignOrder() { this(new RegularOrder()); }
CampaignOrder(Order delegate) { this.delegate = delegate; }
@Override public void add(Beverage beverage) {
delegate.add(beverage);
numberOfBeverages++;
}
@Override public void addAll(Collection<? extends Beverage> beverages) {
delegate.addAll(beverages);
numberOfBeverages += beverages.size();
}
@Override public BigDecimal grandTotal() {
BigDecimal grandTotal = delegate.grandTotal();
if (numberOfBeverages > 2) {
BigDecimal discount = grandTotal.multiply(DISCOUNT_RATE);
grandTotal = grandTotal.subtract(discount);
}
return grandTotal;
}
}
• No refactoring can break CampaignOrder as long as classses keep the contract of the public methods
• CampaignOrder no longer relies on any implementation details of any class
• Composition reduces chances of unforeseen breakage; it will make a codebase more stable 8
Inheritance is inflexible
9
Example: piece of code used by a cafe
interface Beverage {
BigDecimal price();
String description();
}
class Coffee implements Beverage {
@Override public BigDecimal price() { return new BigDecimal("1.99"); }
@Override public String description() { return "Coffee"; }
}
class CoffeeWithMilk extends Coffee {
@Override public BigDecimal price() { return super.price().add(new BigDecimal("0.10")); }
@Override public String description() { return super.description() + ", Milk"; }
}
class CoffeeWithWhip extends Coffee {
@Override public BigDecimal price() { return super.price().add(new BigDecimal("0.15")); }
@Override public String description() { return super.description() + ", Whip"; }
}
class CoffeeWithSugar extends Coffee {
@Override public BigDecimal price() { super.price().add(new BigDecimal("0.05")); }
@Override public String description() { return super.description() + ", Sugar"; }
}
10
New requirement: multiple condiments
• Too many subclasses; we will need to create many subclasses every time we introduce a new condiment
• What if we want to reuse code which is responsible for a condiment for another beverage (e.g. a Tea class) ?
• Inheritance is not flexible enough for this use case
11
Better approach: composition (1/3)
class MilkWrapper implements Beverage {
private final Beverage delegate;
MilkWrapper(Beverage delegate) { this.delegate = delegate; }
@Override public BigDecimal price() { return delegate.price().add(new BigDecimal("0.10")); }
@Override public String description() { return delegate.description() + ", Milk"; }
}
class WhipWrapper implements Beverage {
private final Beverage delegate;
WhipWrapper(Beverage delegate) { this.delegate = delegate; }
@Override public BigDecimal price() { return delegate.price().add(new BigDecimal("0.15")); }
@Override public String description() { return delegate.description() + ", Whip"; }
}
class SugarWrapper implements Beverage {
private final Beverage delegate;
SugarWrapper(Beverage delegate) { this.delegate = delegate; }
@Override public BigDecimal price() { return delegate.price().add(new BigDecimal("0.05")); }
@Override public String description() { return delegate.description() + ", Sugar"; }
} 12
Better approach: composition (2/3)
@Test
void coffeeWithMilk() {
Beverage coffeeWithMilk = new MilkWrapper(new Coffee());
assertThat(coffeeWithMilk.description()).isEqualTo("Coffee, Milk");
assertThat(coffeeWithMilk.price()).isEqualByComparingTo("2.09");
}
@Test
void coffeeWithWhip() {
Beverage coffeeWithWhip = new WhipWrapper(new Coffee());
assertThat(coffeeWithWhip.description()).isEqualTo("Coffee, Whip");
assertThat(coffeeWithWhip.price()).isEqualByComparingTo("2.14");
}
@Test
void coffeeWithSugar() {
Beverage coffeeWithSugar = new SugarWrapper(new Coffee());
assertThat(coffeeWithSugar.description()).isEqualTo("Coffee, Sugar");
assertThat(coffeeWithSugar.price()).isEqualByComparingTo("2.04");
}
13
Better approach: composition (3/3)
@Test
void coffeeWithMilkAndWhip() {
Beverage coffee = new Coffee();
coffee = new MilkWrapper(coffee);
coffee = new WhipWrapper(coffee);
assertThat(coffee.description()).isEqualTo("Coffee, Milk, Whip");
assertThat(coffee.price()).isEqualByComparingTo("2.24");
}
@Test
void coffeeWithMilkAndSugar() {
Beverage coffee = new Coffee();
coffee = new MilkWrapper(coffee);
coffee = new SugarWrapper(coffee);
assertThat(coffee.description()).isEqualTo("Coffee, Milk, Sugar");
assertThat(coffee.price()).isEqualByComparingTo("2.14");
}
@Test
void coffeeWithMilkAndWhipAndSugar() {
Beverage coffee = new Coffee();
coffee = new MilkWrapper(coffee);
coffee = new WhipWrapper(coffee);
coffee = new SugarWrapper(coffee);
assertThat(coffee.description()).isEqualTo("Coffee, Milk, Whip, Sugar");
assertThat(coffee.price()).isEqualByComparingTo("2.29");
}
• Introducing a new condiment doesn't impact any other class (there will be no class explosion)
• Those wrapper classes are highly reusable; they can be reused for anything which implements Beverage
• Much more flexible than inheritance for this use case 14
Conclusion
• Improper use of inheritance can make your code fragile and inflexible
• Using inheritance just for code reuse can lead to an unforeseen
problem in the future
• When you are tempted to use inheritance, using composition instead
can be a good idea
• Further reading:
• Head First Design Patterns
• Design Patterns: Elements of Reusable Object-Oriented Software
15

More Related Content

What's hot

Dependency Inversion Principle
Dependency Inversion PrincipleDependency Inversion Principle
Dependency Inversion PrincipleShahriar Hyder
 
SOLID Principles and The Clean Architecture
SOLID Principles and The Clean ArchitectureSOLID Principles and The Clean Architecture
SOLID Principles and The Clean ArchitectureMohamed Galal
 
Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean ArchitectureRoc Boronat
 
clean code book summary - uncle bob - English version
clean code book summary - uncle bob - English versionclean code book summary - uncle bob - English version
clean code book summary - uncle bob - English versionsaber tabatabaee
 
Spring Framework - MVC
Spring Framework - MVCSpring Framework - MVC
Spring Framework - MVCDzmitry Naskou
 
Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best PracticesTheo Jungeblut
 
Domain Driven Design (DDD)
Domain Driven Design (DDD)Domain Driven Design (DDD)
Domain Driven Design (DDD)Tom Kocjan
 
webpack 101 slides
webpack 101 slideswebpack 101 slides
webpack 101 slidesmattysmith
 
SOLID & IoC Principles
SOLID & IoC PrinciplesSOLID & IoC Principles
SOLID & IoC PrinciplesPavlo Hodysh
 

What's hot (20)

Facade pattern
Facade patternFacade pattern
Facade pattern
 
Dependency injection ppt
Dependency injection pptDependency injection ppt
Dependency injection ppt
 
Dependency Inversion Principle
Dependency Inversion PrincipleDependency Inversion Principle
Dependency Inversion Principle
 
SOLID Principles and The Clean Architecture
SOLID Principles and The Clean ArchitectureSOLID Principles and The Clean Architecture
SOLID Principles and The Clean Architecture
 
Javascript Design Patterns
Javascript Design PatternsJavascript Design Patterns
Javascript Design Patterns
 
Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean Architecture
 
clean code book summary - uncle bob - English version
clean code book summary - uncle bob - English versionclean code book summary - uncle bob - English version
clean code book summary - uncle bob - English version
 
Solid principles
Solid principlesSolid principles
Solid principles
 
Spring Framework - MVC
Spring Framework - MVCSpring Framework - MVC
Spring Framework - MVC
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best Practices
 
Domain Driven Design (DDD)
Domain Driven Design (DDD)Domain Driven Design (DDD)
Domain Driven Design (DDD)
 
Code smells and remedies
Code smells and remediesCode smells and remedies
Code smells and remedies
 
Clean Code
Clean CodeClean Code
Clean Code
 
Express node js
Express node jsExpress node js
Express node js
 
Domain driven design
Domain driven designDomain driven design
Domain driven design
 
webpack 101 slides
webpack 101 slideswebpack 101 slides
webpack 101 slides
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
SOLID & IoC Principles
SOLID & IoC PrinciplesSOLID & IoC Principles
SOLID & IoC Principles
 
An Intro into webpack
An Intro into webpackAn Intro into webpack
An Intro into webpack
 

Similar to Composition over inheritance for flexible, stable code

Java 102 intro to object-oriented programming in java - exercises
Java 102   intro to object-oriented programming in java - exercisesJava 102   intro to object-oriented programming in java - exercises
Java 102 intro to object-oriented programming in java - exercisesagorolabs
 
Combatendo code smells em Java
Combatendo code smells em Java Combatendo code smells em Java
Combatendo code smells em Java Emmanuel Neri
 
Architecture - Part 2 - Transcript.pdf
Architecture - Part 2 - Transcript.pdfArchitecture - Part 2 - Transcript.pdf
Architecture - Part 2 - Transcript.pdfShaiAlmog1
 
Dinheiro em Java: Joda-Money, Money API e além
Dinheiro em Java: Joda-Money, Money API e alémDinheiro em Java: Joda-Money, Money API e além
Dinheiro em Java: Joda-Money, Money API e alémOtávio Santana
 
Refatorando com a API funcional do Java
Refatorando com a API funcional do JavaRefatorando com a API funcional do Java
Refatorando com a API funcional do JavaGiovane Liberato
 
Continously delivering
Continously deliveringContinously delivering
Continously deliveringJames Cowie
 
Solid Software Design Principles
Solid Software Design PrinciplesSolid Software Design Principles
Solid Software Design PrinciplesJon Kruger
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo Ali Parmaksiz
 
Laravel Design Patterns
Laravel Design PatternsLaravel Design Patterns
Laravel Design PatternsBobby Bouwmann
 
Design patterns in the 21st Century
Design patterns in the 21st CenturyDesign patterns in the 21st Century
Design patterns in the 21st CenturySamir Talwar
 
Miscellaneous Features - Part 1 - Transcript.pdf
Miscellaneous Features - Part 1 - Transcript.pdfMiscellaneous Features - Part 1 - Transcript.pdf
Miscellaneous Features - Part 1 - Transcript.pdfShaiAlmog1
 
Learning from GOOS - work in progress
Learning from GOOS - work in progressLearning from GOOS - work in progress
Learning from GOOS - work in progressOlaf Lewitz
 
This is a C# project . I am expected to create as this image shows. .pdf
This is a C# project . I am expected to create as this image shows. .pdfThis is a C# project . I am expected to create as this image shows. .pdf
This is a C# project . I am expected to create as this image shows. .pdfindiaartz
 
Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2Javier Eguiluz
 

Similar to Composition over inheritance for flexible, stable code (20)

Java 102 intro to object-oriented programming in java - exercises
Java 102   intro to object-oriented programming in java - exercisesJava 102   intro to object-oriented programming in java - exercises
Java 102 intro to object-oriented programming in java - exercises
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Combatendo code smells em Java
Combatendo code smells em Java Combatendo code smells em Java
Combatendo code smells em Java
 
Architecture - Part 2 - Transcript.pdf
Architecture - Part 2 - Transcript.pdfArchitecture - Part 2 - Transcript.pdf
Architecture - Part 2 - Transcript.pdf
 
Dinheiro em Java: Joda-Money, Money API e além
Dinheiro em Java: Joda-Money, Money API e alémDinheiro em Java: Joda-Money, Money API e além
Dinheiro em Java: Joda-Money, Money API e além
 
Refatorando com a API funcional do Java
Refatorando com a API funcional do JavaRefatorando com a API funcional do Java
Refatorando com a API funcional do Java
 
C
CC
C
 
DDDesign Challenges
DDDesign ChallengesDDDesign Challenges
DDDesign Challenges
 
Continously delivering
Continously deliveringContinously delivering
Continously delivering
 
Solid Software Design Principles
Solid Software Design PrinciplesSolid Software Design Principles
Solid Software Design Principles
 
Joy of scala
Joy of scalaJoy of scala
Joy of scala
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
 
Laravel Design Patterns
Laravel Design PatternsLaravel Design Patterns
Laravel Design Patterns
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Design patterns in the 21st Century
Design patterns in the 21st CenturyDesign patterns in the 21st Century
Design patterns in the 21st Century
 
Miscellaneous Features - Part 1 - Transcript.pdf
Miscellaneous Features - Part 1 - Transcript.pdfMiscellaneous Features - Part 1 - Transcript.pdf
Miscellaneous Features - Part 1 - Transcript.pdf
 
Spring 2.5
Spring 2.5Spring 2.5
Spring 2.5
 
Learning from GOOS - work in progress
Learning from GOOS - work in progressLearning from GOOS - work in progress
Learning from GOOS - work in progress
 
This is a C# project . I am expected to create as this image shows. .pdf
This is a C# project . I am expected to create as this image shows. .pdfThis is a C# project . I am expected to create as this image shows. .pdf
This is a C# project . I am expected to create as this image shows. .pdf
 
Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2
 

More from Kohei Nozaki

Synchronize access to shared mutable data
Synchronize access to shared mutable dataSynchronize access to shared mutable data
Synchronize access to shared mutable dataKohei Nozaki
 
The Singleton Pattern In Java
The Singleton Pattern In JavaThe Singleton Pattern In Java
The Singleton Pattern In JavaKohei Nozaki
 
Java Generics wildcards
Java Generics wildcardsJava Generics wildcards
Java Generics wildcardsKohei Nozaki
 
JUnit and Mockito tips
JUnit and Mockito tipsJUnit and Mockito tips
JUnit and Mockito tipsKohei Nozaki
 
Overview of Java EE
Overview of Java EEOverview of Java EE
Overview of Java EEKohei Nozaki
 

More from Kohei Nozaki (6)

The State Pattern
The State PatternThe State Pattern
The State Pattern
 
Synchronize access to shared mutable data
Synchronize access to shared mutable dataSynchronize access to shared mutable data
Synchronize access to shared mutable data
 
The Singleton Pattern In Java
The Singleton Pattern In JavaThe Singleton Pattern In Java
The Singleton Pattern In Java
 
Java Generics wildcards
Java Generics wildcardsJava Generics wildcards
Java Generics wildcards
 
JUnit and Mockito tips
JUnit and Mockito tipsJUnit and Mockito tips
JUnit and Mockito tips
 
Overview of Java EE
Overview of Java EEOverview of Java EE
Overview of Java EE
 

Recently uploaded

Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 

Recently uploaded (20)

Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 

Composition over inheritance for flexible, stable code

  • 2. Why favor composition over inheritance? • Inheritance is often overused; composition is a better alternative in many cases • Inheritance can make your code fragile • Inheritance is inflexible 2
  • 3. Inheritance can make your code fragile 3
  • 4. Example: piece of code used by a cafe interface Beverage { BigDecimal price(); String description(); } class Order { private static final BigDecimal TAX_RATE = new BigDecimal("0.1"); private BigDecimal subTotal = BigDecimal.ZERO; void add(Beverage beverage) { subTotal = subTotal.add(beverage.price()); } void addAll(Collection<? extends Beverage> beverages) { for (Beverage beverage : beverages) subTotal = subTotal.add(beverage.price()); } BigDecimal grandTotal() { BigDecimal tax = subTotal.multiply(TAX_RATE); return subTotal.add(tax); } } 4
  • 5. New requirement: discount campaign class CampaignOrder extends Order { private static final BigDecimal DISCOUNT_RATE = new BigDecimal("0.2"); private int numberOfBeverages; @Override void add(Beverage beverage) { super.add(beverage); numberOfBeverages++; } @Override void addAll(Collection<? extends Beverage> beverages) { super.addAll(beverages); numberOfBeverages += beverages.size(); } @Override BigDecimal grandTotal() { BigDecimal grandTotal = super.grandTotal(); if (numberOfBeverages > 2) { BigDecimal discount = grandTotal.multiply(DISCOUNT_RATE); grandTotal = grandTotal.subtract(discount); } return grandTotal; } } 5
  • 6. Refactoring of Order can break CampaignOrder class Order { ... void add(Beverage beverage) { subTotal = subTotal.add(beverage.price()); } void addAll(Collection<? extends Beverage> beverages) { for (Beverage beverage : beverages) // Someone has done refactoring here: // subTotal = subTotal.add(beverage.price()); add(beverage); } ... } • This refactoring has broken CampaignOrder; now CampaignOrder#numberOfBeverages gets incremented twice for every addAll() call • The problem: CampaignOrder relies on an implementation detail of its super class • Using inheritance this way should be avoided because that introduces fragility to the codebase 6
  • 7. Better approach: composition (1/2) interface Order { void add(Beverage beverage); void addAll(Collection<? extends Beverage> beverages); BigDecimal grandTotal(); } class RegularOrder implements Order { private static final BigDecimal TAX_RATE = new BigDecimal("0.1"); private BigDecimal subTotal = BigDecimal.ZERO; @Override public void add(Beverage beverage) { subTotal = subTotal.add(beverage.price()); } @Override public void addAll(Collection<? extends Beverage> beverages) { for (Beverage beverage : beverages) subTotal = subTotal.add(beverage.price()); } @Override public BigDecimal grandTotal() { BigDecimal tax = subTotal.multiply(TAX_RATE); return subTotal.add(tax); } } 7
  • 8. Better approach: composition (2/2) class CampaignOrder implements Order { private static final BigDecimal DISCOUNT_RATE = new BigDecimal("0.2"); private int numberOfBeverages; private final Order delegate; CampaignOrder() { this(new RegularOrder()); } CampaignOrder(Order delegate) { this.delegate = delegate; } @Override public void add(Beverage beverage) { delegate.add(beverage); numberOfBeverages++; } @Override public void addAll(Collection<? extends Beverage> beverages) { delegate.addAll(beverages); numberOfBeverages += beverages.size(); } @Override public BigDecimal grandTotal() { BigDecimal grandTotal = delegate.grandTotal(); if (numberOfBeverages > 2) { BigDecimal discount = grandTotal.multiply(DISCOUNT_RATE); grandTotal = grandTotal.subtract(discount); } return grandTotal; } } • No refactoring can break CampaignOrder as long as classses keep the contract of the public methods • CampaignOrder no longer relies on any implementation details of any class • Composition reduces chances of unforeseen breakage; it will make a codebase more stable 8
  • 10. Example: piece of code used by a cafe interface Beverage { BigDecimal price(); String description(); } class Coffee implements Beverage { @Override public BigDecimal price() { return new BigDecimal("1.99"); } @Override public String description() { return "Coffee"; } } class CoffeeWithMilk extends Coffee { @Override public BigDecimal price() { return super.price().add(new BigDecimal("0.10")); } @Override public String description() { return super.description() + ", Milk"; } } class CoffeeWithWhip extends Coffee { @Override public BigDecimal price() { return super.price().add(new BigDecimal("0.15")); } @Override public String description() { return super.description() + ", Whip"; } } class CoffeeWithSugar extends Coffee { @Override public BigDecimal price() { super.price().add(new BigDecimal("0.05")); } @Override public String description() { return super.description() + ", Sugar"; } } 10
  • 11. New requirement: multiple condiments • Too many subclasses; we will need to create many subclasses every time we introduce a new condiment • What if we want to reuse code which is responsible for a condiment for another beverage (e.g. a Tea class) ? • Inheritance is not flexible enough for this use case 11
  • 12. Better approach: composition (1/3) class MilkWrapper implements Beverage { private final Beverage delegate; MilkWrapper(Beverage delegate) { this.delegate = delegate; } @Override public BigDecimal price() { return delegate.price().add(new BigDecimal("0.10")); } @Override public String description() { return delegate.description() + ", Milk"; } } class WhipWrapper implements Beverage { private final Beverage delegate; WhipWrapper(Beverage delegate) { this.delegate = delegate; } @Override public BigDecimal price() { return delegate.price().add(new BigDecimal("0.15")); } @Override public String description() { return delegate.description() + ", Whip"; } } class SugarWrapper implements Beverage { private final Beverage delegate; SugarWrapper(Beverage delegate) { this.delegate = delegate; } @Override public BigDecimal price() { return delegate.price().add(new BigDecimal("0.05")); } @Override public String description() { return delegate.description() + ", Sugar"; } } 12
  • 13. Better approach: composition (2/3) @Test void coffeeWithMilk() { Beverage coffeeWithMilk = new MilkWrapper(new Coffee()); assertThat(coffeeWithMilk.description()).isEqualTo("Coffee, Milk"); assertThat(coffeeWithMilk.price()).isEqualByComparingTo("2.09"); } @Test void coffeeWithWhip() { Beverage coffeeWithWhip = new WhipWrapper(new Coffee()); assertThat(coffeeWithWhip.description()).isEqualTo("Coffee, Whip"); assertThat(coffeeWithWhip.price()).isEqualByComparingTo("2.14"); } @Test void coffeeWithSugar() { Beverage coffeeWithSugar = new SugarWrapper(new Coffee()); assertThat(coffeeWithSugar.description()).isEqualTo("Coffee, Sugar"); assertThat(coffeeWithSugar.price()).isEqualByComparingTo("2.04"); } 13
  • 14. Better approach: composition (3/3) @Test void coffeeWithMilkAndWhip() { Beverage coffee = new Coffee(); coffee = new MilkWrapper(coffee); coffee = new WhipWrapper(coffee); assertThat(coffee.description()).isEqualTo("Coffee, Milk, Whip"); assertThat(coffee.price()).isEqualByComparingTo("2.24"); } @Test void coffeeWithMilkAndSugar() { Beverage coffee = new Coffee(); coffee = new MilkWrapper(coffee); coffee = new SugarWrapper(coffee); assertThat(coffee.description()).isEqualTo("Coffee, Milk, Sugar"); assertThat(coffee.price()).isEqualByComparingTo("2.14"); } @Test void coffeeWithMilkAndWhipAndSugar() { Beverage coffee = new Coffee(); coffee = new MilkWrapper(coffee); coffee = new WhipWrapper(coffee); coffee = new SugarWrapper(coffee); assertThat(coffee.description()).isEqualTo("Coffee, Milk, Whip, Sugar"); assertThat(coffee.price()).isEqualByComparingTo("2.29"); } • Introducing a new condiment doesn't impact any other class (there will be no class explosion) • Those wrapper classes are highly reusable; they can be reused for anything which implements Beverage • Much more flexible than inheritance for this use case 14
  • 15. Conclusion • Improper use of inheritance can make your code fragile and inflexible • Using inheritance just for code reuse can lead to an unforeseen problem in the future • When you are tempted to use inheritance, using composition instead can be a good idea • Further reading: • Head First Design Patterns • Design Patterns: Elements of Reusable Object-Oriented Software 15