Open/Closed principle (OCP) – Architectural Principles-1

Open/Closed principle (OCP) – Architectural Principles-1

Let’s start this section with a quote from Bertrand Meyer, the person who first wrote the term open/closed principle in 1988:

“Software entities (classes, modules, functions, and so on) should be open for extension but closed for modification.”

OK, but what does that mean? It means you should be able to change the class behaviors from the outside without altering the code.As a bit of history, the first appearance of the OCP in 1988 referred to inheritance, and OOP has evolved a lot since then. Inheritance is still useful, but you should be careful as it is easily misused. Inheritance creates direct coupling between classes. You should, most of the time, opt for composition over inheritance.

“Composition over inheritance” is a principle that suggests it’s better to build objects by combining simple, flexible parts (composition) rather than by inheriting properties from a larger, more complex object (inheritance).

Think of it like building with LEGO® blocks. It’s easier to build and adjust your creation if you put together small blocks (composition) rather than trying to alter a big, single block that already has a fixed shape (inheritance).

Meanwhile, we explore three versions of a business process to illustrate the OCP.

Project – Open Close

First, we look at the Entity and EntityRepository classes used in the code samples:

public record class Entity();
public class EntityRepository
{
    public virtual Task CreateAsync(Entity entity)
        => throw new NotImplementedException();
}

The Entity class represents a simple fictive entity with no properties; consider it anything you’d like. The EntityRepository class has a single CreateAsync method that inserts an instance of an Entity in a database (if it was implemented).

The code sample has few implementation details because it is irrelevant to understanding the OCP. Please assume we implemented the CreateAsync logic using your favorite database.

For the rest of the sample, we refactor the EntityService class, beginning with a version that inherits the EntityRepository class, breaking the OCP:

namespace OCP.NoComposability;
public class EntityService : EntityRepository
{
    public async Task ComplexBusinessProcessAsync(Entity entity)
    {
        // Do some complex things here
        await CreateAsync(entity);
        // Do more complex things here
    }
}

As the namespace implies, the preceding EntityService class offers no composability. Moreover, we tightly coupled it with the EntityRepository class. Since we just covered the composition over inheritance principle, we can quickly isolate the problem: inheritance.As the next step to fix this mess, let’s extract a private _repository field to hold an EntityRepository instance instead:

namespace OCP.Composability;
public class EntityService
{
    private readonly EntityRepository _repository
        = new EntityRepository();
    public async Task ComplexBusinessProcessAsync(Entity entity)
    {
        // Do some complex things here
        await _repository.CreateAsync(entity);
        // Do more complex things here
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *