Now the EntityService is composed of an EntityRepository instance, and there is no more inheritance. However, we still tightly coupled both classes, and it is impossible to change the behavior of the EntityService this way without changing its code.To fix our last issues, we can inject an EntityRepository instance into the class constructor where we set our private field like this:
namespace OCP.DependencyInjection;
public class EntityService
{
private readonly EntityRepository _repository;
public EntityService(EntityRepository repository)
{
_repository = repository;
}
public async Task ComplexBusinessProcessAsync(Entity entity)
{
// Do some complex things here
await _repository.CreateAsync(entity);
// Do more complex things here
}
}
With the preceding change, we broke the tight coupling between the EntityService and the EntityRepository classes. We can also control the behavior of the EntityService class from the outside by deciding what instance of the EntityRepository class we inject into the EntityService constructor. We could even go further by leveraging an abstraction instead of a concrete class and explore this subsequently while covering the DIP.As we just explored, the OCP is a super powerful principle, yet simple, that allows controlling an object from the outside. For example, we could create two instances of the EntityService class with different EntityRepository instances that connect to different databases. Here’s a rough example:
using OCP;
using OCP.DependencyInjection;
// Create the entity in database 1
var repository1 = new EntityRepository(/* connection string 1 */);
var service1 = new EntityService(repository1);
// Create the entity in database 2
var repository2 = new EntityRepository(/* connection string 2 */);
var service2 = new EntityService(repository2);
// Save an entity in two different databases
var entity = new Entity();
await service1.ComplexBusinessProcessAsync(entity);
await service2.ComplexBusinessProcessAsync(entity);
In the preceding code, assuming we implemented the EntityRepository class and configured repository1 and repository2 differently, the result of executing the ComplexBusinessProcessAsync method on service1 and service2 would create the entity in two different databases. The behavior change between the two instances happened without changing the code of the EntityService class; composition: 1, inheritance: 0.
We explore the Strategy pattern—the best way of implementing the OCP—in Chapter 5, Strategy, Abstract Factory, and Singleton. We revisit that pattern and also learn to assemble our program’s well-designed pieces and sew them together using dependency injection in Chapter 6, Dependency Injection.
Next, we explore the principle we can perceive as the most complex of the five, yet the one we will use the less.
Leave a Reply