This week's book giveaway is in the Java in General forum.
We're giving away four copies of Beginning Java 17 Fundamentals: Object-Oriented Programming in Java 17 and have ishori Sharan & Adam L Davis on-line!
See this thread for details.
Win a copy of Beginning Java 17 Fundamentals: Object-Oriented Programming in Java 17 this week in the Java in General forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Ron McLeod
  • Liutauras Vilda
  • Jeanne Boyarsky
Sheriffs:
  • Junilu Lacar
  • Rob Spoor
  • Paul Clapham
Saloon Keepers:
  • Tim Holloway
  • Tim Moores
  • Jesse Silverman
  • Stephan van Hulst
  • Carey Brown
Bartenders:
  • Al Hobbs
  • Piet Souris
  • Frits Walraven

Composition vs Inheritance

 
Greenhorn
Posts: 20
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I've been studying design patterns and read that  Composition leads to better design. When coding, which of these lead to more flexible and maintainable code? Could you explain?
 
Marshal
Posts: 74725
336
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It has been recognised for ages that composition usually leads to better code than inheritance. Please explain more about what you don't understand.
 
Saloon Keeper
Posts: 13500
305
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It's not that easy. While composition in general is more flexible, there are times where it's more clear to use inheritance.

In general, it's good to program to interfaces, meaning your types should try to have interfaces as method parameters and return types. Interfaces should try to be small and simple, so classes that implement them have a clear responsibility. If you have small parts like this, you can use composition very effectively to create larger parts, and you'll often find that all the inheritance you need comes from simply implementing interfaces.
 
j rab
Greenhorn
Posts: 20
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I guess I wanted to if there are certain situations where inheritance would be more efficient than composition and why.
 
j rab
Greenhorn
Posts: 20
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you Stephan van Hulst.
 
Stephan van Hulst
Saloon Keeper
Posts: 13500
305
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Note that everything you can do with inheritance you can also do with composition, if you program to interfaces:

In this sample, both Derived and Composed can do the same thing, and can both be used when a Something is expected. Composed avoids code duplication through delegation, while Derived avoids code duplication through inheritance.

As you can see, inheritance can lead to shorter code, but at the expense of flexibility: Derived is not able to extend another class, while Composed is. An example in the standard API: InputStream is a class, and if you want to make a custom InputStream, you have to extend InputStream in some way, preventing your class from extending other types. InputStream should probably have been an interface.

Knowing when inheritance is the best solution is a matter of experience. In general, try to avoid writing extensible classes unless their most important methods are described by an interface.
 
j rab
Greenhorn
Posts: 20
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Stephan,
Thank you for explaining this to me. This helped me to understand a lot.
 
Sheriff
Posts: 22575
122
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:An example in the standard API: InputStream is a class, and if you want to make a custom InputStream, you have to extend InputStream in some way, preventing your class from extending other types. InputStream should probably have been an interface.


Something that's high on my rant list. The problem is not only there for InputStream, but also for OutputStream, Reader and Writer. There are existing interfaces Readable and Appendable, but neither can handle binary data, and Readable's only method takes a CharBuffer.

A simple solution: introduce some new interfaces:

  • BinaryInput extends Closeable with the read, skip and available methods from InputStream.
  • BinaryOutput extends Closeable, Flushable with the write methods from OutputStream.
  • TextInput extends Closeable with the read, skip and ready methods from Reader.
  • TextOutput extends Closeable, Flushable, Appendable with the write methods from Writer.
  • Markable with the mark and reset methods from InputStream and Reader. Note that method markSupported is not added; that can be achieved by using instanceof. Note that I've made this a separate interface because I hate it that mark and reset can throw exceptions if marking is not supported; instead, these methods should simply not be present (although that can't be achieved without breaking backward compatibility).

  • InputStream would implement BinaryInput; OutputStream would implement BinaryOutput; Reader would implement TextInput ; Writer would implement TextOutput. Note that none of these classes implements Markable; that would be done with classes that return true from markSupported (e.g. BufferedReader).
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 13500
    305
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Yeah it's a huge pain. The first time I found out how much it sucks to have a widely useful class without an accompanying interface was when I tried hacking something together with Observable. After a while I gave up and decided it was much easier to just write my own listener interfaces, and I've never used Observable/Observer since.
     
    Sheriff
    Posts: 67620
    173
    Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    j rab wrote:I guess I wanted to if there are certain situations where inheritance would be more efficient than composition and why.



    Efficient is not a factor. Clarity is the goal.
     
    Campbell Ritchie
    Marshal
    Posts: 74725
    336
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Stephan van Hulst wrote:. . . a widely useful class without an accompanying interface . . .

    Isn't this an even worse example?
     
    Campbell Ritchie
    Marshal
    Posts: 74725
    336
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Bear Bibeault wrote:. . . Efficient is not a factor. Clarity is the goal.

    Search for “write dumb code Brian Goetz”, and you find, would you believe, Brian Goetz telling you to write dumb code. Look at these two links: 1 2, which both tell you the same thing. Bear's clarity of code will translate into efficiency.
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 13500
    305
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Campbell Ritchie wrote:Isn't this an even worse example?



    Yeah, if the standard API didn't have a better alternative. From the Stack documentation:

    Java™ Platform, Standard Edition 8 API Specification wrote:A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class.



    Now, what I find a bit of a pity is that we don't have a Stack interface, and that Deque extends both the Queue and the Stack interfaces. Oh well. I can usually make my intentions clear by declaring my fields like this:
     
    Campbell Ritchie
    Marshal
    Posts: 74725
    336
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Stephan van Hulst wrote:. .  we don't have a Stack interface, . . .

    Yes, that is the real problem. I am sure it would be possible to retrofit Deque and Stack simply by creating this sort of interface:-I am leaving the country before somebody shoots me for using the convention of an I at the beginning . You can also have an advanced stack interface for us Forth users including methods like duplicate duplicate2 nip drop drop2 swap and rotate. [edt] Good idea to call your Deque stack.
     
    Sheriff
    Posts: 16767
    281
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Bear Bibeault wrote:

    j rab wrote:I guess I wanted to if there are certain situations where inheritance would be more efficient than composition and why.



    Efficient is not a factor. Clarity is the goal.


    Amen to that!

    Joshua Bloch's book, Effective Java has an item explaining why you should prefer composition over inheritance. He also has items that explain how inheritance is easy to get wrong and in my experience, many people do get it wrong.
     
    Rob Spoor
    Sheriff
    Posts: 22575
    122
    Eclipse IDE Spring VI Editor Chrome Java Windows
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Stephan van Hulst wrote:The first time I found out how much it sucks to have a widely useful class without an accompanying interface was when I tried hacking something together with Observable.


    Do you have a copy of my rant list? After number one ("InputStream, OutputStream, Reader and Writer are abstract classes, not interfaces"), this is number two: "Observable is an abstract class, not an interface."

    After a while I gave up and decided it was much easier to just write my own listener interfaces, and I've never used Observable/Observer since.


    I actually wrote my own version of Observable, which not only is an interface, but also generic (Observer is also generic). I have classes AbstractObservable and ObservableHelper to help implement Observable.
     
    With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
    reply
      Bookmark Topic Watch Topic
    • New Topic