I'm diving deep into object-oriented programming and grappling with the concept of inheritance. I often hear that composition is generally preferred over inheritance, and I'm curious to know when inheritance can be a problem.
To illustrate my confusion, I've been working on a model involving three types of banking accounts in Java. Here's a brief overview of my BaseAccount class and its subclasses: CurrentAccount, FixedSaverAccount, and SavingsAccount.
I have some specific concerns about the inheritance design:
1. The `earnInterest()` method only applies to two of the subclasses, yet it's required for the CurrentAccount as well, leading to possible misuse. Wouldn't moving this method to the more appropriate subclasses be better?
2. The `withdraw()` method has a confusing implementation. Different accounts have different conditions for withdrawals, which makes it hard to manage when they're all under the same abstract method.
3. There's quite a bit of duplicate code in the `withdraw()` methods, and I thought inheritance was meant to help with avoiding that.
4. If I were to introduce a new account type that doesn't allow deposits or withdrawals, I'd be forced to restructure my inheritance model. This raises the question: is this a bad use of inheritance?
I'd really appreciate any insights or feedback on my model and reasoning.
3 Answers
Keep it up! When designing with inheritance, always consider how much functionality all subclasses will share. If they have significantly different behaviors, that’s a cue to lean more towards composition. In your case with accounts, maybe think about using a common interface or separate classes for actions like deposits and withdrawals to better handle those varied rules without cluttering your design.
You raise a really interesting point about using composition versus inheritance! Generally, inheritance works well when you have a clear "is-a" relationship, but it can get messy if subclasses don't need all the parent class's features. Your example about `earnInterest()` is spot on; it might be better to move that to just the relevant subclasses. You could even consider an interface for `InterestEarnable` with its own implementation for those accounts that actually earn interest, freeing the `BaseAccount` from unnecessary methods.
Definitely agree! It sounds like an interface or a trait could simplify your design a lot. That way, only accounts that need to earn interest would have to implement that method.
On your concerns about confusion with the `withdraw()` method, what if you create a `canWithdraw()` method to handle the logic checks? This can help keep your `withdraw()` implementation cleaner across your subclasses without redundancy. As for your last point, I'd say your design isn't totally flawed, but it could use some tweaking to align better with OOP principles.
Great suggestion! Reducing duplication in that way would streamline things a lot. It might not be a bad inheritance design overall, just needs a bit of refining.

That makes sense! It sounds like using interfaces could really help delineate responsibilities without forcing all the accounts to adhere to methods that don’t apply to them.