O → Open/Closed Principle (Principio Aberto/Fechado)

Postador por : at

Categoria : oop


O Princípio Aberto/Fechado afirma que classes ou métodos devem ser abertos para extensão, mas fechados para modificação.

“Entidades de software… devem ser abertas para extensão, mas fechadas para modificação.”

A declaração na citação acima, a principio, parece ser uma contradição, pois solicita que você programe entidades (classe/função/módulos) para ser abertos e fechados. O OCP exige entidades que podem ser amplamente adaptadas, mas também permanecem inalteradas. Isso nos leva a criar entidades duplicadas com comportamentos especializados por meio de polimorfismo.

Por meio do polimorfismo, podemos estender nossa entidade pai para atender às necessidades da entidade filho, deixando o pai intacto.

Nossa entidade pai servirá como uma classe base abstrata que pode ser reutilizada com especializações adicionadas por meio de herança. No entanto, a entidade original é bloqueada para permitir que o programa seja aberto e fechado.

A vantagem do OCP é que ele minimiza o risco do programa quando você adiciona novos usos para uma entidade. Em vez de refazer a classe base para ajustar um recurso de trabalho em andamento, você cria uma classe derivada separada das classes atualmente presentes em todo o programa.

Podemos então trabalhar nessa classe derivada e exclusiva, confiantes de que quaisquer alterações que fizermos nela não afetarão o pai ou qualquer outra classe derivada.

public class Client {
    private String usageFileFormat;
    private LocalDate lastParse;
    
    
    public void save(){
        //save implementation
    }
    //getters
    //setters
}


public class UsageFileParse {
    private Client client;

    public UsageFileParse(Client client) {
        this.client = client;
    }

    public void parse() {
        switch (client.getUsageFileFormat()) {
            case "XML":
                parseXML();
                break;
            case "CSV":
                paraseCSV();
                break;
            default:
                break;
        }
        this.client.setLastParse(LocalDate.now());
        this.client.save();
    }
    
    private void parseXML(){
        // parse XML interpretation
    }
    
    private void paraseCSV(){
        // parse CSV interpretation
    }
    //getters
    //setters
}

No exemplo acima, podemos ver que teremos que modificar nosso analisador de arquivos sempre que adicionarmos um cliente que nos reporte informações de uso em um formato de arquivo diferente. Isso viola o Princípio Aberto/Fechado. Vamos dar uma olhada em como podemos modificar esse código para torná-lo aberto à extensão:

public class Client {
    private String usageFileFormat;
    private LocalDate lastParse;


    public void save(){
        //save implementation
    }
    //getters
    //setters
}

public abstract class Parser {
    abstract void parser(String usageFile);
}

public class XmlParser extends Parser {

    @Override
    void parser(String usageFile) {
        //implement parser XMl
    }
}
public class CsvParser extends Parser {

    @Override
    void parser(String usageFile) {
        //implement parser CSV
    }
}
public class UsageFileParse {
    private Client client;
    private Parser parser;
    public UsageFileParse(Client client, Parser parser) {
        this.client = client;
        this.parser = parser;
    }

    public void parse(String usageFile) {
        this.parser.parser(usageFile);
        this.client.setLastParse(LocalDate.now());
        this.client.save();
    }
    //getters
    //setters
}

Com essa refatoração, tornamos possível adicionar novos parsers sem alterar nenhum código. Qualquer comportamento adicional exigirá apenas a adição de uma nova classe. Isso torna UsageFileParserreutilizáveis e, em muitos casos, nos manterá em conformidade com o Princípio da Responsabilidade Única, incentivando-nos a criar classes menores e mais focadas.

Vamos falar no próximo artigo sobre LSP (Liskov Substitution Principle) .