Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Upcoming SlideShare
What to Upload to SlideShare
Next
Download to read offline and view in fullscreen.

0

Share

Download to read offline

Favouring Composition - The Groovy Way

Download to read offline

Slides from my APACHECON@HOME 2020 talk - "Favouring Composition - The Groovy Way".

Most developers I met agree that composition is better than inheritance. However, in most codebases, we see the use of inheritance where composition would have been a better design choice. Then why are the Java developers falling into this trap? It is easy to implement inheritance over composition. But we end up paying for the consequences in terms of reduced maintainability. Can language offer anything for the developers to implement composition? In this presentation, I walk you through what Groovy has to offer to make sure implementing composition is as easy as inheritance, if not simpler. I dive into three techniques for applying the composition in your Groovy applications. We start with the technique of delegation and see how easy it is to implement compositions. We uncover the limitations of this technique and introduce traits. After walking through plenty of code examples covering various aspects of using traits, we briefly touch upon functional composition, since Groovy also supports functional programming.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all
  • Be the first to like this

Favouring Composition - The Groovy Way

  1. 1. Favoring Composition - The Groovy Way Naresha K @naresha_k https://blog.nareshak.com/ APACHECON @HOME Spt, 29th – Oct. 1st 2020
  2. 2. About me Developer, Architect & Tech Excellence Coach Founder & Organiser Bangalore Groovy User Group 2
  3. 3. Object-Oriented Maturity Model! 3
  4. 4. 2 No inheritance. Mostly Procedural code 1 Inheritance Everywhere 0 No inheritance. Mostly Procedural code Evolution of OO Programmer 4
  5. 5. INHERITANCE 5
  6. 6. 6
  7. 7. 2 No inheritance. Mostly Procedural code 1 Inheritance Everywhere 0 No inheritance. Mostly Procedural code Evolution of OO Programmer 7
  8. 8. Liskov Substitution Principle 8
  9. 9. 2 Favour composition 1 Inheritance Everywhere 0 No inheritance. Mostly Procedural code Evolution of OO Programmer 9
  10. 10. Favour Composition to Inheritance 10
  11. 11. The difference between theory and practice is in theory somewhat smaller than in practice 11
  12. 12. Inheritance is Easy 12
  13. 13. List<String> phoneNumbers = new ArrayList<>() phoneNumbers += ['19876512345', '19876512346', ‘919876512347', '49876512348'] println phoneNumbers 13
  14. 14. List<String> phoneNumbers = new ArrayList<>() phoneNumbers += ['19876512345', '19876512346', ‘919876512347', '49876512348'] println phoneNumbers println phoneNumbers.collect { "+" + it } 14
  15. 15. List<String> phoneNumbers = new ArrayList<>() phoneNumbers += ['19876512345', '19876512346', ‘919876512347', '49876512348'] println phoneNumbers println phoneNumbers.collect { "+" + it } println phoneNumbers.find { it == '919876512347' } 15
  16. 16. List<String> phoneNumbers = new ArrayList<>() phoneNumbers += ['19876512345', '19876512346', ‘919876512347', '49876512348'] println phoneNumbers println phoneNumbers.collect { "+" + it } println phoneNumbers.find { it == '919876512347' } println phoneNumbers.usPhoneNumbers(); Method usPhoneNumbers() not available in ArrayList 16
  17. 17. class PhoneNumbers extends ArrayList<String> { List<String> usPhoneNumbers() { iterator().findAll { number -> number.startsWith("1") } } } 17
  18. 18. PhoneNumbers phoneNumbers = new PhoneNumbers() phoneNumbers += ['19876512345', '19876512346', '919876512347', '49876512348'] println phoneNumbers println phoneNumbers.collect { "+" + it } println phoneNumbers.find { it == '919876512347' } println phoneNumbers.usPhoneNumbers(); 18
  19. 19. @ToString(includePackage = false, includes = "data") class PhoneNumbers { List<String> data = [] String find(Closure closure) { data.find { closure } } public <T> List<T> collect(Closure<T> closure) { data.collect(closure) } List<String> usPhoneNumbers() { data.findAll { number -> number.startsWith("1") } } PhoneNumbers plus(List list) { new PhoneNumbers(data: data + list) } } 19
  20. 20. @ToString(includePackage = false, includes = "data") class PhoneNumbers { List<String> data = [] String find(Closure closure) { data.find { closure } } public <T> List<T> collect(Closure<T> closure) { data.collect(closure) } List<String> usPhoneNumbers() { data.findAll { number -> number.startsWith("1") } } PhoneNumbers plus(List list) { new PhoneNumbers(data: data + list) } } class PhoneNumbers extends ArrayList<String> { List<String> usPhoneNumbers() { iterator().findAll { number -> number.startsWith("1") } } } 20
  21. 21. @ToString(includePackage = false, includes = "data") class PhoneNumbers { @Delegate List<String> data = [] List<String> usPhoneNumbers() { data.findAll { number -> number.startsWith("1") } } } 21
  22. 22. @ToString(includePackage = false, includes = "data") class PhoneNumbers { @Delegate List<String> data = [] List<String> usPhoneNumbers() { data.findAll { number -> number.startsWith("1") } } } PhoneNumbers phoneNumbers phoneNumbers = ['19876512345', '19876512346', '919876512347', '49876512348'] as PhoneNumbers println phoneNumbers println phoneNumbers.collect { "+" + it } println phoneNumbers.find { it == '919876512347' } println phoneNumbers.usPhoneNumbers(); 22
  23. 23. 23
  24. 24. Bird sunny = new Bird() sunny.fly() 24
  25. 25. Bird sunny = new Bird() sunny.fly() ButterFly aButterFly = new ButterFly() aButterFly.fly() 25
  26. 26. Bird sunny = new Bird() sunny.fly() ButterFly aButterFly = new ButterFly() aButterFly.fly() interface Flyable { void fly() } 26
  27. 27. Bird sunny = new Bird() sunny.fly() ButterFly aButterFly = new ButterFly() aButterFly.fly() interface Flyable { void fly() } List<Flyable> fliers = [sunny, aButterFly] fliers.each { flier -> flier.fly() } 27
  28. 28. class Bird implements Flyable { @Override void fly() { println "Flying..." } } class ButterFly implements Flyable { @Override void fly() { println "Flying..." } } 28
  29. 29. class Bird implements Flyable { @Override void fly() { println "Flying..." } } class ButterFly implements Flyable { @Override void fly() { println "Flying..." } } Potential violation of DRY principle 29
  30. 30. 30
  31. 31. class DefaultFlyable implements Flyable { @Override void fly() { println "Flying..." } } class Bird implements Flyable { private Flyable defaultFlyable = new DefaultFlyable() @Override void fly() { defaultFlyable.fly() } } 31
  32. 32. class DefaultFlyable implements Flyable { @Override void fly() { println "Flying..." } } class Bird implements Flyable { @Delegate private Flyable defaultFlyable = new DefaultFlyable() } interface Flyable { void fly() } 32
  33. 33. trait Flyable { void fly() { println "Flying..." } } class Bird implements Flyable {} class ButterFly implements Flyable {} 33
  34. 34. public interface Flyable { public abstract void fly() } public static class Flyable$Trait$Helper { public static void fly(Flyable $self) { $self.println('Flying...') } } public class Bird implements Flyable { public void fly() { Flyable$Trait$Helper.fly(this) } } trait Flyable 34
  35. 35. interface Flyable { void fly() } trait FlyableTrait implements Flyable { @Override void fly() { println "Flying..." } } 35
  36. 36. class Actor implements Singer, Dancer {} Actor actor = new Actor() actor.sing() actor.dance() trait Singer { void sing() { println "Singing" } } trait Dancer { void dance() { println "Dancing" } } Composing multiple behaviours 36
  37. 37. trait BusinessObject { UUID uuid = UUID.randomUUID() } class Product implements BusinessObject { } Product product = new Product() println product.uuid Composing state 37
  38. 38. public interface BusinessObject { public abstract java.util.UUID getUuid() public abstract void setUuid(java.util.UUID value) } public static interface BusinessObject$Trait$FieldHelper {} public abstract static class BusinessObject$Trait$Helper { public static java.util.UUID getUuid(BusinessObject $self) { (( $self ) as BusinessObject$Trait$FieldHelper).BusinessObject__uuid$get() } public static void setUuid(BusinessObject $self, java.util.UUID value) { (( $self ) as BusinessObject$Trait$FieldHelper).BusinessObject__uuid$set(value) } } 38
  39. 39. public class Product implements BusinessObject, BusinessObject$Trait$FieldHelper { private java.util.UUID BusinessObject__uuid } 39
  40. 40. class Person { } Person person = new Person() person.fly() Composing at Runtime 40
  41. 41. class Person { } Person person = new Person() Flyable passanger = boardPlane(person) passanger.fly() Flyable boardPlane(Person person) { person.withTraits FlyableTrait } 41
  42. 42. trait JavaProgrammer { def codeObjectOriented() { println 'Coding OOP' } } trait GroovyProgrammer extends JavaProgrammer { def codeFunctional() { println 'Coding FP' } } class Developer implements GroovyProgrammer {} Developer raj = new Developer() raj.codeFunctional() raj.codeObjectOriented() Trait extending another Trait 42
  43. 43. trait Reader { def read() { println 'Reading'} } trait Evaluator { def eval() { println 'Evaluating'} } trait Printer { def print() { println 'Printing'} } trait Repl implements Reader, Evaluator, Printer { } class GroovyRepl implements Repl{} Repl groovyRepl = new GroovyRepl() groovyRepl.read() groovyRepl.eval() groovyRepl.print() Trait extending multiple Traits 43
  44. 44. interface MyInterface { default void doSomething() { println "Doing" } } // is equivalent to trait MyInterface { void doSomething() { println "Doing" } } default methods in Groovy Interfaces 44
  45. 45. Function Composition 45
  46. 46. List<String> firstNamesOfDevs(List<Developer> devs, Closure devSelector) { List<Developer> selectedDevs = devSelector(devs) selectedDevs.collect { it.name } } Closure groovyDevSelector = … Closure javaDevSelector = … Closure javaAndGroovyDevSelector = ? println firstNamesOfDevs(developers, javaAndGroovyDevSelector) 46
  47. 47. List<String> firstNamesOfDevs(List<Developer> devs, Closure devSelector) { List<Developer> selectedDevs = devSelector(devs) selectedDevs.collect { it.name } } Closure groovyDevSelector = … Closure javaDevSelector = … Closure javaAndGroovyDevSelector = groovyDevSelector << javaDevSelector println firstNamesOfDevs(developers, javaAndGroovyDevSelector) 47
  48. 48. Happy Composing Thank You APACHECON @HOME Spt, 29th – Oct. 1st 2020

Slides from my APACHECON@HOME 2020 talk - "Favouring Composition - The Groovy Way". Most developers I met agree that composition is better than inheritance. However, in most codebases, we see the use of inheritance where composition would have been a better design choice. Then why are the Java developers falling into this trap? It is easy to implement inheritance over composition. But we end up paying for the consequences in terms of reduced maintainability. Can language offer anything for the developers to implement composition? In this presentation, I walk you through what Groovy has to offer to make sure implementing composition is as easy as inheritance, if not simpler. I dive into three techniques for applying the composition in your Groovy applications. We start with the technique of delegation and see how easy it is to implement compositions. We uncover the limitations of this technique and introduce traits. After walking through plenty of code examples covering various aspects of using traits, we briefly touch upon functional composition, since Groovy also supports functional programming.

Views

Total views

157

On Slideshare

0

From embeds

0

Number of embeds

11

Actions

Downloads

0

Shares

0

Comments

0

Likes

0

×