The Base Bean antipattern occurs when a concrete domain class inherits from a utility class because it wants to use the utility methods in that utility class. This is also commonly referred to as inheritance for implementation.
Inheriting from a utility class just to be able to use its methods is a bad way to use inheritance and violates the Liskov substitution principle. It does not make sense in terms of the semantics of the domain and can therefore be potentially confusing for other developers.
Instead of inheriting from the utility class, the concrete domain class should simply delegate to the utility class by calling its methods. This is in line with the design maxim Favor composition over inheritance.
Imagine we want to create a phone book to store the names and phone numbers of customers. We want the phone book to store information in the form of a map, where the name of the customer is the key and the phone number is the value.
Base Bean occurs if we subclass the Map class to create our PhoneBook class. We have done this because we want to get the behavior of the map for our phone book.
Bad developer, no biscuit.
Instead, we should have created our PhoneBook class and have it contain a map that it uses to store the information.
- The domain class relies on the internals of the utility class which may be outside of the developer's control. When the utility class changes, the domain class will be affected. Overall, this decreases the maintainability of the system.
- Base Bean leads to decreased understandability because the way inheritance is used does not make sense in terms of the domain that is modeled.
- This practice also confuses the meaning of the domain class and pollutes it with methods that are not really part of the concept it represents. In this way, the domain class no longer has a single responsibility as it also takes on the functionality of the utility class.
- The domain class may have no intention of fulfilling the contract of the utility class.
Related design maxims
- Favor composition over inheritance
- Avoid inheritance for implementation
- Liskov substitution principle
- Single responsibility principle
- Don't burn your base class
- Design by contract