• Fat Cats Boardgame
  • Wicket UI Library
  • About Me

Java and Wicket web development thoughts, tutorials, and tips

roman@coderdreams.com
Coder DreamsCoder Dreams
  • Fat Cats Boardgame
  • Wicket UI Library
  • About Me

Why you should favor composition over inheritance

March 8, 2020 Posted by Roman Sery java, software design No Comments

Composition has always had some advantages over inheritance. Creating deep inheritance hierarchies leads to brittle/inflexible code when you are trying to make changes deep in the hierarchy.

There have been two key improvements made to interfaces in Java 8 and above, that make the argument for composition even stronger:

  • Default methods – This allows you define methods with a default implementation inside of interfaces.  Classes that implement the interface can choose to override default methods, or keep them as is.
  • Private/Static methods – In this way, it becomes easier to write default functionality for an interface using private helper methods that should not be exposed as part of the interface.

Let’s look at an example where we can use composition along with the new functionality of interfaces.

Building a Human with composition

Let’s create a class that will represent a biological human. We can imagine that a human being is composed of many different systems that work together in order for the human to function. There’s the skeletal system, cardiovascular system, immune system, nervous system, and so on.

In this oversimplified example, we can think of each system as being an interface. Our human class will implement each of these interfaces:

Great! Now, what if we want to create a new biological organism that shares a lot of traits with humans, but doesn’t have a skeletal system? This illustrates the major advantage of composition. We can do this by simply creating a new class that implements only 2 out of the 3 systems:

Using default and private methods

Now we can write a simple skeletal system interface and see how a human might implement it. We will demonstrate private and default interface methods, as well as interface fields:

public interface SkeletalSystem {
    List<Bone> bones = new ArrayList<>();
    List<Joint> joints = new ArrayList<>();

    abstract String getSex();

    default void addBone(Bone b) {
        bones.add(b);
        recalculateJointHealth();
    }

    default void addJoint(Joint j) {
        joints.add(j);
        recalculateJointHealth();
    }

    default int getBoneMass() {
        return bones.stream().map(Bone::getMass).reduce(0, Integer::sum);
    }

    private void recalculateJointHealth() {
        for(Joint j : joints) {
            //... do something
        }
    }

    public class Bone {
        private String name;
        private int mass;

        public Bone(String name, int mass) {
            this.name = name;
            this.mass = mass;
        }

        public int getMass() { return mass; }
        public void setMass(int mass) { this.mass = mass; }

        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }

    public class Joint {
        private Bone b1;
        private Bone b2;
        private int strength;

        public Joint(Bone b1, Bone b2, int strength) {
            this.b1 = b1;
            this.b2 = b2;
            this.strength = strength;
        }

        public Bone getB1() { return b1; }
        public void setB1(Bone b1) { this.b1 = b1; }

        public Bone getB2() { return b2; }
        public void setB2(Bone b2) { this.b2 = b2; }

        public int getStrength() { return strength; }
        public void setStrength(int strength) { this.strength = strength; }
    }
}

For brevity, SkeletalSystem is presented as a fully self-contained interface. It defines the Bone and Joint classes and collections for storing them. There are default methods for adding bones and joints, as well as private helper methods.

public class Human implements SkeletalSystem {
    private final String sex;
    private int height;
    private int weight;

    public Human(String sex) {
        this.sex = sex;

        Bone lfemur = new Bone("LFemur", 50);
        Bone lHip = new Bone("lHip", 50);
        addBone(lfemur);
        addBone(lHip);

        addJoint(new Joint(lfemur, lHip, 100));

        System.out.println(getBoneMass());
    }

    public int getHeight() { return height; }
    public void setHeight(int height) { this.height = height; }

    public int getWeight() { return weight; }
    public void setWeight(int weight) { this.weight = weight; }

    @Override
    public String getSex() { return sex; }
}

Our Human class defines it’s own data fields and uses the SkeletalSystem to add some bones and joints. We could also create helper methods that could initialize the SkeletalSystem using a standard human bone structure.

Conclusion

I hope this example will help you choose composition over inheritance when it’s appropriate. Rember this basic rule when deciding:

  • Choose inheritance when modeling a “is-a” relationship.
    • A senior citizen is a citizen.
    • A standing desk is a desk.
  • Choose composition when modeling a “has-a” relationship.
    • A human has a skeletal system, cardiovasicular system, etc.
    • A car has an engine, a transmission, gas tank, etc.
No Comments
Share
2

About Roman Sery

I've been a software developer for over 10 years and still loving Java!

You also might be interested in

Creating single click buttons with Wicket

Aug 16, 2019

How to create a Wicket button component to prevent users from clicking buttons multiple times in succession.

Using interfaces to make Java enums more flexible

Jul 10, 2019

Imagine you need to easily customize your enumerations for each customer but want to have one codebase? Here's how

Wicket quick tip #4: Change default AjaxChannel to Active

Jul 7, 2020

Change the default behavior of Wicket's ajax request processing in order to avoid some common bugs.

Categories

  • aws
  • customization
  • database
  • debugging
  • enum
  • java
  • models
  • performance
  • projects
  • react
  • software design
  • Spring
  • tool
  • Uncategorized
  • wicket

Recent Posts

  • Rent Day
  • Self-contained Wicket Fragments
  • Pros and cons of unit testing
  • Themeable React Monopoly board
  • Please dont use client-specific release branches

Recent Comments

  • TCI Express Thanks for sharing such insightful information. TCI Express truly stands out as the best air logistics company, offering fast, secure, and efficient air express and cold chain transportation services....

    Tracking down a bug in production Wicket application ·  March 25, 2025

  • Tom Error: A zip file cannot include itself Can you please correct the plugin part so it doesn't use the same folder as input?

    Deploying Spring Boot app to AWS Beanstalk with Nginx customization ·  September 3, 2021

  • Golfman: Reality always wins I've used both Wicket and front-end JS frameworks and, having worked extensively on both, I can tell you that "Speed of development" is definitely NOT with the JS frameworks. You basically end up...

    Five reasons you should use Apache Wicket ·  August 29, 2021

  • Kiriller Sorry can not agree with you, wicket might be a well built technical framework. But the advantages of using a front-end framework like react.js and vue.js can not be beaten by Wicket nowadays. - Speed...

    Five reasons you should use Apache Wicket ·  August 23, 2021

  • Bernd Lauert Sorry but i have to refute your claims with the following arguments: 1. the Wicket community may be small but it is also very responsive, you usually get a helpful answer from the core devs on the...

    Five reasons you should use Apache Wicket ·  July 1, 2021

Archives

  • May 2021
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • October 2019
  • September 2019
  • August 2019
  • July 2019

Contact Me

Send Message
Prev Next