Composition Over Inheritance – Does It Violate the DRY Principle?

compositiondryinheritance

For example, consider I have a class for other classes to extend:

public class LoginPage {
    public String userId;
    public String session;
    public boolean checkSessionValid() {
    }
}

and some subclasses:

public class HomePage extends LoginPage {

}

public class EditInfoPage extends LoginPage {

}

In fact, the subclass has not any methods to override, also I would not access the HomePage in generic way, i.e.: I would not do something like:

for (int i = 0; i < loginPages.length; i++) {
    loginPages[i].doSomething();
}

I just want to reuse the login page. But according to https://stackoverflow.com/a/53354, I should prefer composition here because I don't need the interface LoginPage, so I don't use inheritance here:

public class HomePage {
    public LoginPage loginPage;
}

public class EditInfoPage {
    public LoginPage loginPage;
}

but the problem comes here, at the new version, the code:

public LoginPage loginPage;

duplicates when a new class is added. And if LoginPage needs setter and getter, more codes need to be copied:

public LoginPage loginPage;

private LoginPage getLoginPage() {
    return this.loginPage;
}
private void setLoginPage(LoginPage loginPage) {
    this.loginPage = loginPage;
}

So my question is, is "composition over inheritance" violating "dry principle"?

Best Answer

Er wait you're concerned that repeating

public LoginPage loginPage;

in two places violates DRY? By that logic

int x;

can now only ever exist in one object in the entire code base. Bleh.

DRY is a good thing to keep in mind but come on. Besides

... extends LoginPage

is getting duplicated in your alternative so even being anal about DRY wont make sense of this.

Valid DRY concerns tend to focus on identical behavior needed in multiple places being defined in multiple places such that a need to change this behavior ends up requiring a change in multiple places. Make decisions in one place and you will only need to change them in one place. It doesn't mean only one object can ever hold a reference to your LoginPage.

DRY shouldn't be followed blindly. If you're duplicating because copy and paste is easier than thinking up a good method or class name then you're probably in the wrong.

But if you want to put the same code in a different place because that different place is subject to a different responsibility and is likely to need to change independently then it's probably wise to relax your enforcement of DRY and let this identical behavior have a different identity. It's the same kind of thinking that goes into forbidding magic numbers.

DRY isn't just about what the code looks like. It's about not spreading the details of an idea around with mindless repetition forcing maintainers to fix things using mindless repetition. It's when you try to tell yourself that the mindless repetition is just your convention that things are headed in a real bad way.

What I think you are really trying to complain about is called boilerplate code. Yes, using composition rather than inheritance demands boilerplate code. Nothing gets exposed for free, you have to write code that exposes it. With that boilerplate comes state flexibility, the ability to narrow the exposed interface, to give things different names that are appropriate for their level of abstraction, good ol indirection, and you're using what you're composed of from the outside, not the inside, so you're facing it's normal interface.

But yes, it's a lot of extra keyboard typing. As long as I can prevent the yo-yo problem of bouncing up and down an inheritance stack as I read the code it's worth it.

Now it's not that I refuse to ever use inheritance. One of my favorite uses is to give exceptions new names:

public class MyLoginPageWasNull extends NullPointerException{}
Related Topic