SlideShare a Scribd company logo
1 of 29
Download to read offline
Combining Objects with
Composition
POODR CH8
Goal
▸ Techniques of OO composition with example
▸ Discussion of the relative strengths and weakness of
composition and inheritance (and mixins)
Code reuse Approaches?
▸ Copy and Paste
▸ Inheritance
▸ Mixin
▸ Composition
Definition from Wiki
▸ A way to combine simple objects or data types into more
complex ones.
▸ https://en.wikipedia.org/wiki/Object_composition
1 class Bicycle
2 attr_reader :size, :chain, :tire_size
3 def initialize(args = {})
4 @size = args[:size]
5 @chain = args[:chain] || default_chain
6 @tire_size = args[:tire_size] ||
7 default_tire_size
8 post_initialize(args)
9 end
10
11 def spares
12 { tire_size: tire_size,
13 chain: chain }.merge(local_spares)
14 end
15
16 def default_tire_size
17 fail NotImplementedError
18 end
19
20 def post_initialize(_args)
21 nil
22 end
23
24 def local_spares
25 {}
26 end
27
28 def default_chain
29 '10-speed'
30 end
31 end
1 class RoadBike < Bicycle
2 attr_reader :tape_color
3 def post_initialize(args)
4 @tape_color = args[:tape_color]
5 end
6
7 def local_spares
8 { tape_color: tape_color }
9 end
10
11 def default_tire_size
12 '23'
13 end
14 end
1 class MountainBike < Bicycle
2 attr_reader :front_shock, :rear_shock
3 def post_initialize(args)
4 @front_shock = args[:front_shock]
5 @rear_shock = args[:rear_shock]
6 end
7
8 def local_spares
9 { rear_shock: rear_shock }
10 end
11
12 def default_tire_size
13 '2.1'
14 end
15 end
A Bicycle has-a Parts
Bicycle Parts
1
MountainBikeParts
RoadBikeParts
1 class Bicycle
2 attr_reader :size, :chain, :tire_size
3 def initialize(args = {})
4 @size = args[:size]
5 @chain = args[:chain] || default_chain
6 @tire_size = args[:tire_size] ||
7 default_tire_size
8 post_initialize(args)
9 end
10
11 def spares
12 { tire_size: tire_size,
13 chain: chain }.merge(local_spares)
14 end
15
16 def default_tire_size
17 fail NotImplementedError
18 end
19
20 def post_initialize(_args)
21 nil
22 end
23
24 def local_spares
25 {}
26 end
27
28 def default_chain
29 '10-speed'
30 end
31 end
1 class Bicycle
2 attr_reader :size, :parts
3 def initialize(args = {})
4 @size = args[:size]
5 @parts = args[:parts]
6 end
7
8 def spares
9 parts.spares
10 end
11 end
1 class Bicycle
2 attr_reader :size, :parts
3 def initialize(args = {})
4 @size = args[:size]
5 @parts = args[:parts]
6 end
7
8 def spares
9 parts.spares
10 end
11 end
1 class Parts
2 attr_reader :chain, :tire_size
3 def initialize(args={})
4 @chain = args[:chain] || default_chain
5 @tire_size = args[:tire_size] ||
6 default_tire_size
7 post_initialize(args)
8 end
9
10 def spares
11 { tire_size: tire_size,
12 chain: chain }.merge(local_spares)
13 end
14
15 def default_tire_size
16 fail NotImplementedError
17 end
18
19 def post_initialize(_args)
20 nil
21 end
22
23 def local_spares
24 {}
25 end
26
27 def default_chain
28 '10-speed'
29 end
30 end
1 class RoadBike < Bicycle
2 attr_reader :tape_color
3 def post_initialize(args)
4 @tape_color = args[:tape_color]
5 end
6
7 def local_spares
8 { tape_color: tape_color }
9 end
10
11 def default_tire_size
12 '23'
13 end
14 end
1 class MountainBike < Bicycle
2 attr_reader :front_shock, :rear_shock
3 def post_initialize(args)
4 @front_shock = args[:front_shock]
5 @rear_shock = args[:rear_shock]
6 end
7
8 def local_spares
9 { rear_shock: rear_shock }
10 end
11
12 def default_tire_size
13 '2.1'
14 end
15 end
1 class RoadBikeParts < Parts
2 attr_reader :tape_color
3 def post_initialize(args)
4 @tape_color = args[:tape_color]
5 end
6
7 def local_spares
8 { tape_color: tape_color }
9 end
10
11 def default_tire_size
12 '23'
13 end
14 end
1 class MountainBikeParts < Parts
2 attr_reader :front_shock, :rear_shock
3 def post_initialize(args)
4 @front_shock = args[:front_shock]
5 @rear_shock = args[:rear_shock]
6 end
7
8 def local_spares
9 { rear_shock: rear_shock }
10 end
11
12 def default_tire_size
13 '2.1'
14 end
15 end
1 road_bike = RoadBike.new(
2 size: 'L',
3 tape_color: 'red'
4 )
1 road_bike = Bicycle.new(
2 size: 'L',
3 parts: RoadBikeParts.new(tape_color: 'red')
4 )
Instantiate
A Bicycle has-a Parts which with many Part
Bicycle Parts
1
Part
1..*
1 class Parts
2 attr_reader :parts
3 def initialize(parts)
4 @parts = parts
5 end
6
7 def spares
8 parts.select(&:needs_spare)
9 end
10 end
1 class Parts
2 attr_reader :chain, :tire_size
3 def initialize(args={})
4 @chain = args[:chain] || default_chain
5 @tire_size = args[:tire_size] ||
6 default_tire_size
7 post_initialize(args)
8 end
9
10 def spares
11 { tire_size: tire_size,
12 chain: chain }.merge(local_spares)
13 end
14
15 def default_tire_size
16 fail NotImplementedError
17 end
18
19 def post_initialize(_args)
20 nil
21 end
22
23 def local_spares
24 {}
25 end
26
27 def default_chain
28 '10-speed'
29 end
30 end
1 class Part
2 attr_reader :name, :description, :needs_spare
3 def initialize(args)
4 @name = args[:name]
5 @description = args[:description]
6 @needs_spare = args.fetch(:needs_spare,
7 true)
8 end
9 end
1 class RoadBikeParts < Parts
2 attr_reader :tape_color
3 def post_initialize(args)
4 @tape_color = args[:tape_color]
5 end
6
7 def local_spares
8 { tape_color: tape_color }
9 end
10
11 def default_tire_size
12 '23'
13 end
14 end
1 class MountainBikeParts < Parts
2 attr_reader :front_shock, :rear_shock
3 def post_initialize(args)
4 @front_shock = args[:front_shock]
5 @rear_shock = args[:rear_shock]
6 end
7
8 def local_spares
9 { rear_shock: rear_shock }
10 end
11
12 def default_tire_size
13 '2.1'
14 end
15 end
1 road_bike = Bicycle.new(
2 size: 'L',
3 tape_color: 'red'
4 )
1 road_bike = Bicycle.new(
2 size: 'L',
3 parts: RoadBikeParts.new(tape_color: 'red')
4 )
Instantiate
1 chain = Part.new(name: 'chain', description:
2 '10-speed')
3 road_tire = Part.new(name: 'tire_size',
4 description: '23')
5 tape = Part.new(name: 'tape_color', description:
6 'red')
7
8 road_bike = Bicycle.new(
9 size: 'L',
10 parts: Parts.new([chain,
11 road_tire,
12 tape])
13 )
Making the Parts more like an Array
▸ Add size method in to Parts class manually
▸ How about each, sort and more…
▸ Let Parts inherit Array
▸ Some behaviors may not be expected !!
▸ There is no perfect solution
A middle ground between complexity and usability
1 require 'forwardable'
2 class Parts
3 extend Forwardable
4 def_delegators :@parts, :size, :each
5 include Enumerable
6
7 def initialize(parts)
8 @parts = parts
9 end
10
11 def spares
12 parts.select(&:needs_spare)
13 end
14 end
Knowledge leakage
1 chain = Part.new(name: 'chain', description:
2 '10-speed')
3 road_tire = Part.new(name: 'tire_size',
4 description: '23')
5 tape = Part.new(name: 'tape_color', description:
6 'red')
7
8 road_bike = Bicycle.new(
9 size: 'L',
10 parts: Parts.new([chain,
11 road_tire,
12 tape])
13 )
Need knowledge of how to create part
Need to know road bike’s all parts
Manufacturing parts
▸ Everything would be easier if you could describe the
different bikes and then use your descriptions to magically
manufacture the correct Parts object for any bike.
▸ 2-dimensional array
▸ Unlike a hash, this simple 2-dimensional array provides
no structural information.
1 road_config =
2 [['chain', '10-speed'],
3 %w(tire_size 23),
4 %w(tape_color red)]
5 mountain_config =
6 [['chain', '10-speed'],
7 ['tire_size', '2.1'],
8 ['front_shock', 'Manitou', false],
9 %w(rear_shock Fox)]
1 module PartsFactory
2 def self.build(config,
3 part_class = Part, parts_class = Parts)
4 parts_class.new(
5 config.collect do|part_config|
6 part_class.new(
7 name: part_config[0],
8 description: part_config[1],
9 needs_spare: part_config.fetch(2,
10 true))
11 end
12 )
13 end
14 end
1 road_bike = Bicycle.new(
2 size: 'L',
3 parts: PartsFactory.build(road_config)
4 )
1 module PartsFactory
2 def self.build(config,
3 part_class = Part, parts_class = Parts)
4 parts_class.new(
5 config.collect do|part_config|
6 part_class.new(
7 name: part_config[0],
8 description: part_config[1],
9 needs_spare: part_config.fetch(2,
10 true))
11 end
12 )
13 end
14 end
1 class Part
2 attr_reader :name, :description, :needs_spare
3 def initialize(args)
4 @name = args[:name]
5 @description = args[:description]
6 @needs_spare = args.fetch(:needs_spare,
7 true)
8 end
9 end
1 require 'ostruct'
2 module PartsFactory
3 def self.build(config, parts_class = Parts)
4 parts_class.new(
5 config.collect { |part_config|
6 create_part(part_config)
7 }
8 )
9 end
10
11 def self.create_part(part_config)
12 OpenStruct.new(
13 name: part_config[0],
14 description: part_config[1],
15 needs_spare: part_config.fetch(2, true)
16 )
17 end
18 end
Aggregation
▸ Aggregation is exactly like composition except that the
contained object has an independent life.
Inheritance vs. Composition
Inheritance Composition
Delegation of Message Free Cost
Hierarchy of Class Cost Free
Inheritance: What will happen when I’m wrong?
▸ That is, Incorrectly modeled hierarchy
▸ Making small changes near the top of hierarchy break
everything.
▸ You will be forced to duplicate or restructure code.
▸ Impossibility of adding behavior when new subclasses
represent a mixture of types.
▸ Might be used by others for purposes you did not anticipate
Using Inheritance when satisfied …
▸ Reasonable
▸ Big changes in behavior can be achieved via small
changes in code.
▸ Usable
▸ Easily create new subclasses.
▸ Exemplary
Drawbacks of Mixin
▸ Too powerful, so its easy to abuse.
▸ Refactoring anti-pattern: God object
▸ You still have one object with the same number of
public methods.
▸ The rules of coupling and cohesion start to come into
play
How about composition
▸ Small objects, SRP, transparent.
▸ Simple and pluggable objects that are easy to extend and
have a high tolerance for change.
▸ Cost of management small parts collection, but relatively
easy to control.
Concepts
▸ Inheritance
▸ Subclass Is-A specialization of Superclass.
▸ Mixin
▸ Class A take A Role Of Module B (Module B is Adjective)
▸ Composition
▸ Class A Has-A class B
Conclusion
▸ Can't figure out what to do? Use composition.
▸ The key to improving your design skills is to attempt these 
techniques, accept your errors cheerfully, remain detached
 from past design decisions, and refactor mercilessly.
Reference
▸ Re-use in OO: Inheritance, Composition and Mixins.
▸ Composition over Mixins
▸ Factory pattern - Design patterns in ruby

More Related Content

What's hot

Seistech SQL code
Seistech SQL codeSeistech SQL code
Seistech SQL code
Simon Hoyle
 

What's hot (20)

The MySQL Query Optimizer Explained Through Optimizer Trace
The MySQL Query Optimizer Explained Through Optimizer TraceThe MySQL Query Optimizer Explained Through Optimizer Trace
The MySQL Query Optimizer Explained Through Optimizer Trace
 
Data Wrangling with dplyr
Data Wrangling with dplyrData Wrangling with dplyr
Data Wrangling with dplyr
 
Partition and conquer large data in PostgreSQL 10
Partition and conquer large data in PostgreSQL 10Partition and conquer large data in PostgreSQL 10
Partition and conquer large data in PostgreSQL 10
 
Read/Import data from flat/delimited files into R
Read/Import data from flat/delimited files into RRead/Import data from flat/delimited files into R
Read/Import data from flat/delimited files into R
 
Five
FiveFive
Five
 
Advanced SQL Queries
Advanced SQL QueriesAdvanced SQL Queries
Advanced SQL Queries
 
What Have The Properties Ever Done For Us
What Have The Properties Ever Done For UsWhat Have The Properties Ever Done For Us
What Have The Properties Ever Done For Us
 
Quick reference for spark sql
Quick reference for spark sqlQuick reference for spark sql
Quick reference for spark sql
 
Practical Introduction to Web scraping using R
Practical Introduction to Web scraping using RPractical Introduction to Web scraping using R
Practical Introduction to Web scraping using R
 
Seistech SQL code
Seistech SQL codeSeistech SQL code
Seistech SQL code
 
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebBDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
 
Explore Data using dplyr
Explore Data using dplyrExplore Data using dplyr
Explore Data using dplyr
 
Quick reference for hql
Quick reference for hqlQuick reference for hql
Quick reference for hql
 
ALL BASIC SQL SERVER QUERY
ALL BASIC SQL SERVER QUERY ALL BASIC SQL SERVER QUERY
ALL BASIC SQL SERVER QUERY
 
4-Cm10
4-Cm104-Cm10
4-Cm10
 
The Ring programming language version 1.5.2 book - Part 9 of 181
The Ring programming language version 1.5.2 book - Part 9 of 181The Ring programming language version 1.5.2 book - Part 9 of 181
The Ring programming language version 1.5.2 book - Part 9 of 181
 
Visualization of Supervised Learning with {arules} + {arulesViz}
Visualization of Supervised Learning with {arules} + {arulesViz}Visualization of Supervised Learning with {arules} + {arulesViz}
Visualization of Supervised Learning with {arules} + {arulesViz}
 
Using Optimizer Hints to Improve MySQL Query Performance
Using Optimizer Hints to Improve MySQL Query PerformanceUsing Optimizer Hints to Improve MySQL Query Performance
Using Optimizer Hints to Improve MySQL Query Performance
 
Java EE 8新機能解説 -Bean Validation 2.0編-
Java EE 8新機能解説 -Bean Validation 2.0編-Java EE 8新機能解説 -Bean Validation 2.0編-
Java EE 8新機能解説 -Bean Validation 2.0編-
 
Python decorators (中文)
Python decorators (中文)Python decorators (中文)
Python decorators (中文)
 

Similar to Poodr ch8-composition

Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
ConFoo
 
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code styleRuby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Anton Shemerey
 
C-Sharp Arithmatic Expression Calculator
C-Sharp Arithmatic Expression CalculatorC-Sharp Arithmatic Expression Calculator
C-Sharp Arithmatic Expression Calculator
Neeraj Kaushik
 
Optimization based Chassis Design
Optimization based Chassis DesignOptimization based Chassis Design
Optimization based Chassis Design
Altair
 
INFORMATIVE ESSAYThe purpose of the Informative Essay assignme.docx
INFORMATIVE ESSAYThe purpose of the Informative Essay assignme.docxINFORMATIVE ESSAYThe purpose of the Informative Essay assignme.docx
INFORMATIVE ESSAYThe purpose of the Informative Essay assignme.docx
carliotwaycave
 

Similar to Poodr ch8-composition (20)

Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
 
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code styleRuby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
 
R Programming: Transform/Reshape Data In R
R Programming: Transform/Reshape Data In RR Programming: Transform/Reshape Data In R
R Programming: Transform/Reshape Data In R
 
Do snow.rwn
Do snow.rwnDo snow.rwn
Do snow.rwn
 
Refatoração + Design Patterns em Ruby
Refatoração + Design Patterns em RubyRefatoração + Design Patterns em Ruby
Refatoração + Design Patterns em Ruby
 
OOD - Object orientated design
OOD - Object orientated designOOD - Object orientated design
OOD - Object orientated design
 
C-Sharp Arithmatic Expression Calculator
C-Sharp Arithmatic Expression CalculatorC-Sharp Arithmatic Expression Calculator
C-Sharp Arithmatic Expression Calculator
 
More than syntax
More than syntaxMore than syntax
More than syntax
 
Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()
 
Optimization based Chassis Design
Optimization based Chassis DesignOptimization based Chassis Design
Optimization based Chassis Design
 
Java Lab Manual
Java Lab ManualJava Lab Manual
Java Lab Manual
 
Intro to Rails 4
Intro to Rails 4Intro to Rails 4
Intro to Rails 4
 
JavaProgrammingManual
JavaProgrammingManualJavaProgrammingManual
JavaProgrammingManual
 
Migrating legacy data
Migrating legacy dataMigrating legacy data
Migrating legacy data
 
R Programming: Numeric Functions In R
R Programming: Numeric Functions In RR Programming: Numeric Functions In R
R Programming: Numeric Functions In R
 
MySQL Optimizer: What’s New in 8.0
MySQL Optimizer: What’s New in 8.0MySQL Optimizer: What’s New in 8.0
MySQL Optimizer: What’s New in 8.0
 
Improving go-git performance
Improving go-git performanceImproving go-git performance
Improving go-git performance
 
Fosdem2017 Scientific computing on Jruby
Fosdem2017  Scientific computing on JrubyFosdem2017  Scientific computing on Jruby
Fosdem2017 Scientific computing on Jruby
 
Webinar slides: MORE secrets of ClickHouse Query Performance. By Robert Hodge...
Webinar slides: MORE secrets of ClickHouse Query Performance. By Robert Hodge...Webinar slides: MORE secrets of ClickHouse Query Performance. By Robert Hodge...
Webinar slides: MORE secrets of ClickHouse Query Performance. By Robert Hodge...
 
INFORMATIVE ESSAYThe purpose of the Informative Essay assignme.docx
INFORMATIVE ESSAYThe purpose of the Informative Essay assignme.docxINFORMATIVE ESSAYThe purpose of the Informative Essay assignme.docx
INFORMATIVE ESSAYThe purpose of the Informative Essay assignme.docx
 

Recently uploaded

CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 

Recently uploaded (20)

%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 

Poodr ch8-composition

  • 2. Goal ▸ Techniques of OO composition with example ▸ Discussion of the relative strengths and weakness of composition and inheritance (and mixins)
  • 3. Code reuse Approaches? ▸ Copy and Paste ▸ Inheritance ▸ Mixin ▸ Composition
  • 4. Definition from Wiki ▸ A way to combine simple objects or data types into more complex ones. ▸ https://en.wikipedia.org/wiki/Object_composition
  • 5. 1 class Bicycle 2 attr_reader :size, :chain, :tire_size 3 def initialize(args = {}) 4 @size = args[:size] 5 @chain = args[:chain] || default_chain 6 @tire_size = args[:tire_size] || 7 default_tire_size 8 post_initialize(args) 9 end 10 11 def spares 12 { tire_size: tire_size, 13 chain: chain }.merge(local_spares) 14 end 15 16 def default_tire_size 17 fail NotImplementedError 18 end 19 20 def post_initialize(_args) 21 nil 22 end 23 24 def local_spares 25 {} 26 end 27 28 def default_chain 29 '10-speed' 30 end 31 end 1 class RoadBike < Bicycle 2 attr_reader :tape_color 3 def post_initialize(args) 4 @tape_color = args[:tape_color] 5 end 6 7 def local_spares 8 { tape_color: tape_color } 9 end 10 11 def default_tire_size 12 '23' 13 end 14 end 1 class MountainBike < Bicycle 2 attr_reader :front_shock, :rear_shock 3 def post_initialize(args) 4 @front_shock = args[:front_shock] 5 @rear_shock = args[:rear_shock] 6 end 7 8 def local_spares 9 { rear_shock: rear_shock } 10 end 11 12 def default_tire_size 13 '2.1' 14 end 15 end
  • 6. A Bicycle has-a Parts Bicycle Parts 1 MountainBikeParts RoadBikeParts
  • 7. 1 class Bicycle 2 attr_reader :size, :chain, :tire_size 3 def initialize(args = {}) 4 @size = args[:size] 5 @chain = args[:chain] || default_chain 6 @tire_size = args[:tire_size] || 7 default_tire_size 8 post_initialize(args) 9 end 10 11 def spares 12 { tire_size: tire_size, 13 chain: chain }.merge(local_spares) 14 end 15 16 def default_tire_size 17 fail NotImplementedError 18 end 19 20 def post_initialize(_args) 21 nil 22 end 23 24 def local_spares 25 {} 26 end 27 28 def default_chain 29 '10-speed' 30 end 31 end 1 class Bicycle 2 attr_reader :size, :parts 3 def initialize(args = {}) 4 @size = args[:size] 5 @parts = args[:parts] 6 end 7 8 def spares 9 parts.spares 10 end 11 end
  • 8. 1 class Bicycle 2 attr_reader :size, :parts 3 def initialize(args = {}) 4 @size = args[:size] 5 @parts = args[:parts] 6 end 7 8 def spares 9 parts.spares 10 end 11 end 1 class Parts 2 attr_reader :chain, :tire_size 3 def initialize(args={}) 4 @chain = args[:chain] || default_chain 5 @tire_size = args[:tire_size] || 6 default_tire_size 7 post_initialize(args) 8 end 9 10 def spares 11 { tire_size: tire_size, 12 chain: chain }.merge(local_spares) 13 end 14 15 def default_tire_size 16 fail NotImplementedError 17 end 18 19 def post_initialize(_args) 20 nil 21 end 22 23 def local_spares 24 {} 25 end 26 27 def default_chain 28 '10-speed' 29 end 30 end
  • 9. 1 class RoadBike < Bicycle 2 attr_reader :tape_color 3 def post_initialize(args) 4 @tape_color = args[:tape_color] 5 end 6 7 def local_spares 8 { tape_color: tape_color } 9 end 10 11 def default_tire_size 12 '23' 13 end 14 end 1 class MountainBike < Bicycle 2 attr_reader :front_shock, :rear_shock 3 def post_initialize(args) 4 @front_shock = args[:front_shock] 5 @rear_shock = args[:rear_shock] 6 end 7 8 def local_spares 9 { rear_shock: rear_shock } 10 end 11 12 def default_tire_size 13 '2.1' 14 end 15 end 1 class RoadBikeParts < Parts 2 attr_reader :tape_color 3 def post_initialize(args) 4 @tape_color = args[:tape_color] 5 end 6 7 def local_spares 8 { tape_color: tape_color } 9 end 10 11 def default_tire_size 12 '23' 13 end 14 end 1 class MountainBikeParts < Parts 2 attr_reader :front_shock, :rear_shock 3 def post_initialize(args) 4 @front_shock = args[:front_shock] 5 @rear_shock = args[:rear_shock] 6 end 7 8 def local_spares 9 { rear_shock: rear_shock } 10 end 11 12 def default_tire_size 13 '2.1' 14 end 15 end
  • 10. 1 road_bike = RoadBike.new( 2 size: 'L', 3 tape_color: 'red' 4 ) 1 road_bike = Bicycle.new( 2 size: 'L', 3 parts: RoadBikeParts.new(tape_color: 'red') 4 ) Instantiate
  • 11. A Bicycle has-a Parts which with many Part Bicycle Parts 1 Part 1..*
  • 12. 1 class Parts 2 attr_reader :parts 3 def initialize(parts) 4 @parts = parts 5 end 6 7 def spares 8 parts.select(&:needs_spare) 9 end 10 end 1 class Parts 2 attr_reader :chain, :tire_size 3 def initialize(args={}) 4 @chain = args[:chain] || default_chain 5 @tire_size = args[:tire_size] || 6 default_tire_size 7 post_initialize(args) 8 end 9 10 def spares 11 { tire_size: tire_size, 12 chain: chain }.merge(local_spares) 13 end 14 15 def default_tire_size 16 fail NotImplementedError 17 end 18 19 def post_initialize(_args) 20 nil 21 end 22 23 def local_spares 24 {} 25 end 26 27 def default_chain 28 '10-speed' 29 end 30 end 1 class Part 2 attr_reader :name, :description, :needs_spare 3 def initialize(args) 4 @name = args[:name] 5 @description = args[:description] 6 @needs_spare = args.fetch(:needs_spare, 7 true) 8 end 9 end
  • 13. 1 class RoadBikeParts < Parts 2 attr_reader :tape_color 3 def post_initialize(args) 4 @tape_color = args[:tape_color] 5 end 6 7 def local_spares 8 { tape_color: tape_color } 9 end 10 11 def default_tire_size 12 '23' 13 end 14 end 1 class MountainBikeParts < Parts 2 attr_reader :front_shock, :rear_shock 3 def post_initialize(args) 4 @front_shock = args[:front_shock] 5 @rear_shock = args[:rear_shock] 6 end 7 8 def local_spares 9 { rear_shock: rear_shock } 10 end 11 12 def default_tire_size 13 '2.1' 14 end 15 end
  • 14. 1 road_bike = Bicycle.new( 2 size: 'L', 3 tape_color: 'red' 4 ) 1 road_bike = Bicycle.new( 2 size: 'L', 3 parts: RoadBikeParts.new(tape_color: 'red') 4 ) Instantiate 1 chain = Part.new(name: 'chain', description: 2 '10-speed') 3 road_tire = Part.new(name: 'tire_size', 4 description: '23') 5 tape = Part.new(name: 'tape_color', description: 6 'red') 7 8 road_bike = Bicycle.new( 9 size: 'L', 10 parts: Parts.new([chain, 11 road_tire, 12 tape]) 13 )
  • 15. Making the Parts more like an Array ▸ Add size method in to Parts class manually ▸ How about each, sort and more… ▸ Let Parts inherit Array ▸ Some behaviors may not be expected !! ▸ There is no perfect solution
  • 16. A middle ground between complexity and usability 1 require 'forwardable' 2 class Parts 3 extend Forwardable 4 def_delegators :@parts, :size, :each 5 include Enumerable 6 7 def initialize(parts) 8 @parts = parts 9 end 10 11 def spares 12 parts.select(&:needs_spare) 13 end 14 end
  • 17. Knowledge leakage 1 chain = Part.new(name: 'chain', description: 2 '10-speed') 3 road_tire = Part.new(name: 'tire_size', 4 description: '23') 5 tape = Part.new(name: 'tape_color', description: 6 'red') 7 8 road_bike = Bicycle.new( 9 size: 'L', 10 parts: Parts.new([chain, 11 road_tire, 12 tape]) 13 ) Need knowledge of how to create part Need to know road bike’s all parts
  • 18. Manufacturing parts ▸ Everything would be easier if you could describe the different bikes and then use your descriptions to magically manufacture the correct Parts object for any bike. ▸ 2-dimensional array ▸ Unlike a hash, this simple 2-dimensional array provides no structural information.
  • 19. 1 road_config = 2 [['chain', '10-speed'], 3 %w(tire_size 23), 4 %w(tape_color red)] 5 mountain_config = 6 [['chain', '10-speed'], 7 ['tire_size', '2.1'], 8 ['front_shock', 'Manitou', false], 9 %w(rear_shock Fox)] 1 module PartsFactory 2 def self.build(config, 3 part_class = Part, parts_class = Parts) 4 parts_class.new( 5 config.collect do|part_config| 6 part_class.new( 7 name: part_config[0], 8 description: part_config[1], 9 needs_spare: part_config.fetch(2, 10 true)) 11 end 12 ) 13 end 14 end 1 road_bike = Bicycle.new( 2 size: 'L', 3 parts: PartsFactory.build(road_config) 4 )
  • 20. 1 module PartsFactory 2 def self.build(config, 3 part_class = Part, parts_class = Parts) 4 parts_class.new( 5 config.collect do|part_config| 6 part_class.new( 7 name: part_config[0], 8 description: part_config[1], 9 needs_spare: part_config.fetch(2, 10 true)) 11 end 12 ) 13 end 14 end 1 class Part 2 attr_reader :name, :description, :needs_spare 3 def initialize(args) 4 @name = args[:name] 5 @description = args[:description] 6 @needs_spare = args.fetch(:needs_spare, 7 true) 8 end 9 end 1 require 'ostruct' 2 module PartsFactory 3 def self.build(config, parts_class = Parts) 4 parts_class.new( 5 config.collect { |part_config| 6 create_part(part_config) 7 } 8 ) 9 end 10 11 def self.create_part(part_config) 12 OpenStruct.new( 13 name: part_config[0], 14 description: part_config[1], 15 needs_spare: part_config.fetch(2, true) 16 ) 17 end 18 end
  • 21. Aggregation ▸ Aggregation is exactly like composition except that the contained object has an independent life.
  • 22. Inheritance vs. Composition Inheritance Composition Delegation of Message Free Cost Hierarchy of Class Cost Free
  • 23. Inheritance: What will happen when I’m wrong? ▸ That is, Incorrectly modeled hierarchy ▸ Making small changes near the top of hierarchy break everything. ▸ You will be forced to duplicate or restructure code. ▸ Impossibility of adding behavior when new subclasses represent a mixture of types. ▸ Might be used by others for purposes you did not anticipate
  • 24. Using Inheritance when satisfied … ▸ Reasonable ▸ Big changes in behavior can be achieved via small changes in code. ▸ Usable ▸ Easily create new subclasses. ▸ Exemplary
  • 25. Drawbacks of Mixin ▸ Too powerful, so its easy to abuse. ▸ Refactoring anti-pattern: God object ▸ You still have one object with the same number of public methods. ▸ The rules of coupling and cohesion start to come into play
  • 26. How about composition ▸ Small objects, SRP, transparent. ▸ Simple and pluggable objects that are easy to extend and have a high tolerance for change. ▸ Cost of management small parts collection, but relatively easy to control.
  • 27. Concepts ▸ Inheritance ▸ Subclass Is-A specialization of Superclass. ▸ Mixin ▸ Class A take A Role Of Module B (Module B is Adjective) ▸ Composition ▸ Class A Has-A class B
  • 28. Conclusion ▸ Can't figure out what to do? Use composition. ▸ The key to improving your design skills is to attempt these  techniques, accept your errors cheerfully, remain detached  from past design decisions, and refactor mercilessly.
  • 29. Reference ▸ Re-use in OO: Inheritance, Composition and Mixins. ▸ Composition over Mixins ▸ Factory pattern - Design patterns in ruby