SOLID principles using Typescript
SOLID principles using Typescript
The following article explains SOLID principles using Typescript.
Here are more articles about Typescript:
Introducing Typescript: Language features
SOLID is an acronym for the first five object-oriented design(OOD) principles by Robert C. Martin, popularly known as @UncleBob.
The five SOLID principles are:
- Single responsibility principle: a class should have one, and only one, reason to change;
- Open-closed principle: it should be possible to extend the behavoir of a class without modifying it;
- Liskov Substitution principle: subclasses should be substitutable for their superclasses;
- Interface segregation principle: many small, client-specific interfaces are better than one general purpose interface;
- Dependency inversion principle: depends on abstractions not concretions;
These principles, make it easy for a programmer to develop software that are easy to maintain and extend. They also make it easy for developers to avoid code smells, easily refactor code, and are also a part of the agile or adaptive software development.
The Single Responsibility Principle (SRP)
The SRP requires that a class should have only one reason to change. A class that follows this principle performs just few related tasks. You don’t need to limit your thinking to classes when considering the SRP. You can apply the principle to methods or modules, ensuring that they do just one thing and therefore have just one reason to change.
Example – wrong way
The class Task
defines properties related to the model, but it also defines the data access method to save the entity on a generic data source:
UML
Code
Example – right way
The Task
class can be divided between Task
class, that takes care of model description and TaskRepository
that is responsabile for storing the data.
UML
Code
The Open-closed Princple (OCP)
Software entities should be open for extension but closed for modification.
The risk of changing an existing class is that you will introduce an inadvertent change in behaviour. The solution is create another class that overrides the behaviour of the original class. By following the OCP, a component is more likely to contain maintainable and re-usable code.
Example – right way
The CreditCard
class describes a method to calculate the monthlyDiscount()
. The monthlyDiscount()
depends on the type of Card, which can be : Silver or Gold. To change the monthly discount calc, you should create another class which overrides the monthlyDiscount()
Method.
The solution is to create two new classes: one for each type of card.
UML
Code
The Liskov Substitution Principle (LSP)
Child classes should never break the parent class’ type definitions.
The concept of this principle was introduced by Barbara Liskov in a 1987 conference keynote and later published in a paper together with Jannette Wing in 1994.
As simple as that, a subclass should override the parent class methods in a way that does not break functionality from a client’s point of view.
Example
In the following example ItalyPostalAddress
, UKPostalAddress
and USAPostalAddress
extend one common class: PostalAddress
.
The AddressWriter
class refers PostalAddress
: the writer
parameter can be of three different sub-types.
UML
Code
The Interface Segregation Principle (ISP)
It is quite common to find that an interface is in essence just a description of an entire class. The ISP states that we should write a series of smaller and more specific interfaces that are implemented by the class. Each interface provides an single behavior.
Example – wrong way
The following Printer
interface makes it impossible to implement a printer that can print and copy, but not staple:
Example – right way
The following example shows an alternative approach that groups methods into more specific interfaces. It describe a number of contracts that could be implemented individually by a simple printer or simple copier or by a super printer:
The Dependency inversion principle (DIP)
The DIP simply states that high-level classes shouldn’t depend on low-level components, but instead depend on an abstraction.
Example – wrong way
The high-level WindowSwitch
depends on the lower-level CarWindow
class:
UML
Code
Example – right way
To follow the DIP, the class WindowSwitch
should references an interface (IWindow
) that is implemented by the object CarWindow
:
UML
Code
Final thoughts
Typescript make it possible to bring all of the principles and practices of OOP into your software, using SOLID principles to guide your design patterns.
Here’s the GitHub repository containing the full examples.