Skip to the content.
Skip to the content.

SOLID (2/5)

Um dos conceitos mais solicitados hoje no mundo do desenvolvimento é o conhecimento de SOLID. Nesse post, vamos explorar o OCP - Open-Closed Principle.

OCP - Open-Closed Principle

O princípio aberto-fechado diz que um software deve estar aberto para extensão e fechado para modificação. Isso significa que podemos estender o funcionamento de um software adicionando novos módulos, sem precisar modificar o código existente.

Vamos usar como exemplo uma classe responsável por cobranças:

copy
public enum TipoCobranca {
	Credito,
	Debito
}

public class Cobranca {

	public void GerarCobranca(TipoCobranca tipoCobranca, decimal valor){
		switch (tipoCobranca){
			case TipoCobranca.Credito:
				// Lógica de cobrança por crédito
				break;
			case TipoCobranca.Debito:
				// Lógica de cobrança por débito
				break;
			default:
				throw new ArgumentException("Tipo de cobrança inválido");
		}
	}

}

Imagine que, no futuro, precisemos adicionar uma nova forma de cobrança, como PIX. Para isso, precisaríamos modificar a classe Cobranca, o que vai contra o princípio aberto-fechado.

A palavra-chave aqui é abstração. Precisamos abstrair a lógica de cobrança para que possamos adicionar novas formas de cobrança sem modificar a classe existente. Para resolver isso, podemos criar uma interface que define o contrato de cobrança e implementar diferentes classes para cada tipo de cobrança:

copy
public interface ICobranca {
	void GerarCobranca(decimal valor);
}

public class CobrancaCredito : ICobranca {
	public void GerarCobranca(decimal valor) {
		// Lógica de cobrança por crédito
	}
}

public class CobrancaDebito : ICobranca {
	public void GerarCobranca(decimal valor) {
		// Lógica de cobrança por débito
	}
}

public class CobrancaPix : ICobranca {
	public void GerarCobranca(decimal valor) {
		// Lógica de cobrança por PIX
	}
}

Note que agora, se quisermos adicionar uma nova forma de cobrança (como CobrancaPix), não precisamos modificar nenhuma classe existente, apenas criar uma nova classe que implementa a interface ICobranca. Isso mantém o software aberto para extensão e fechado para modificação.

Como usar essas classes?

Para utilizar essas implementações, podemos criar um contexto que trabalhe com a abstração:

copy
public class ProcessadorCobranca {
	private readonly ICobranca _cobranca;
	
	public ProcessadorCobranca(ICobranca cobranca) {
		_cobranca = cobranca;
	}
	
	public void ProcessarPagamento(decimal valor) {
		_cobranca.GerarCobranca(valor);
	}
}

// Uso:
var cobrancaPix = new CobrancaPix();
var processador = new ProcessadorCobranca(cobrancaPix);
processador.ProcessarPagamento(100.00m);

Dessa forma, o ProcessadorCobranca não precisa conhecer os detalhes específicos de cada tipo de cobrança, trabalhando apenas com a abstração ICobranca.