Skip to main content

Design Decisions: Why use final classes

· 4 min read
Iain Cambridge

I've started to document the design decisions made for Parthenon. One of the main decisions made was to make classes that aren't meant to be extended to be final. There are many schools of thought when it comes to development. With many people having different opinions about when and why to use final classes, I thought I would add my opinion to the mix.

Decision

The decision was made to make classes that aren't meant to be extended final. All final classes should have an interface that matches their publicly available methods.

Open/Closed Principle

Some people like SOLID principles, and some people don't. Personally, I think trying to apply SOLID principles when they make sense is the way to go. Like all things, they shouldn't be blindly applied. Within Parthenon, there has been attempt to apply SOLID rules. For those not aware Open/Closed Principle is that a module should be open to extension but closed to modifications. To apply that principle to Parthenon, I've used final classes and interfaces.

Each module is open to extension in the fact you can extend what it does by implementing an interface. This will allow you to change almost every part of how Parthenon does things by adding in and using your own extensions. If you want to be able to just extend how something works by doing something before or after the execution there is always the decorator pattern.

It is closed to modification in the fact that each implementation in Parthenon's core that is not meant to be extended uses a final class.

Limiting maintainance requirements

Another reason for making classes final is it limits the surface area for which other developers can interact with. When a developer is able to extend a class, they can become reliant on how the class functions internally. This means that any changes to how the class functions internally could affect how their application functions and add in breaking changes.

By having classes as final the only considerations I need to have are related to the inputs and outputs. These are generally covered by the actual interface that is being implemented.

When would I not use final classes?

I would not advise using final classes on in-house applications. I've worked with people who kept saying all classes should be final. These people would say things such as "If it's extendable, we'll need to maintain it if someone extends it. If it's final we won't." This line of thought works only if your code is going to be distributed. However, within an in-house application, if someone does something you need to maintain it. It doesn't matter if you originally made it final or if you don't like it. You're literally getting paid to maintain the code.

Also, if they're working on the code base and they want to do something but you've made it final, then they can just remove the final keyword. Making things final only works when they can't just remove the final keyword so things like libraries, sdk, etc that are being distributed in packages.

Conclusion

While I'm sure, not everyone is going to like the thought process here and think it's over engineering or whatever. It's how I want to develop; therefore it's how it's been developed. If someone can provide a good reason why something shouldn't be final then that will be taken onboard and the final keyword removed.

If you're interested in the other design decisions, you can see what has been documented so far at the design decisions documentation page.

To get started with Parthenon, which is a general functionality bundle for Symfony, you can check out the getting started guide

Loading...