Princípio do Aberto/Fechado
Autor: Kênia | Publicado: 2016-11-13T18:58:00-02:00





De acordo com Meyer (1997), classes deverão ser abertas para extensão, mas fechadas para modificação. Esse é o OCP, Princípio do Aberto/Fechado. Esse princípio estabelece que as classes que estendam alguma outra classe devem utilizar as funcionalidades da classe estendida sem que essa superclasse precise ser alterada. Isso significa que se o princípio for obedecido, o acréscimo de novas funcionalidades em um software não implica em alteração de suas classes, mas apenas na introdução de novas.
Veja o exemplo do método totalPrice, desenvolvido para calcular preço de alguns tipos de peças:

public class Part {
public double totalPrice(Part[ ] parts) {
double total = 0.0;
for (int i = 0; i &lt; parts.length; i++) {
total += parts[i].getPrice( );
}
return total;
}
}

public class MotherBoard extends Part{
public double getPrice( ){
super.getPrice();
}
}

public class Memory extends Part{
public double getPrice( ){
super.getPrice();
}
}

E se devido ao aumento de imposto repentino de alguns produtos fosse necessário cobrar um preço adicional sobre certas peças? Por exemplo, se os preços de memória e de placa mãe tivessem que ser majorado em 30% e 45%, respectivamente, uma solução seria alterar o método totalPtrice para:

public double totalPrice(Part[ ] parts) {
&nbsp;&nbsp;&nbsp; double total = 0.0;
&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; parts.length; i++) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (parts[i] instanceof Motherboard)
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; total += (1.45* parts[i].getPrice( ));
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else if (parts[i] instanceof Memory)
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; total += (1.30* parts[i].getPrice( ));
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; else total += parts[i].getPrice( );
}
return total;
}

Imagine que fosse necessário agora diferenciar uma nova peça, seria necessário inserir um novo if na condição e ela poderia ficar cada vez maior a medida que a lista de produtos com preços diferenciados aumentasse. Essa nova estrutura funciona como um switch e deve ser evitada, pois, prejudica a manutenibilidade do código uma vez que, a necessidade de uma alteração pode desencadear uma série de outras alterações e tornar o código cada vez mais complexo.

Uma melhor solução é evitar o uso do switch, preservar o totalPrice original e embutir as variações de preço nos métodos getPrice de cada peça, como mostra o código a seguir.

public class Part {
private double basePrice;
public void setPrice(double price){basePrice=price;}
public double getPrice( ){ return basePrice;}

public double totalPrice(Part[ ] parts) {
double total = 0.0;
for (int i = 0; i &lt; parts.length; i++) {
total += parts[i].getPrice( );
}
return total;
}

}

public class MotherBoard extends Part{
public double getPrice( ){
return 1.45*super.getPrice();
}
}

public class Memory extends Part{
public double getPrice( ){
return 1.30*super.getPrice();
}
}

Na solução acima, o acesso ao atributo que contém o preço base foi restringido e as subclasses passaram a utilizar o método de forma específica. Nesse caso, a classe Part ficou aberta para extensão e fechada para modificação e não precisa ser alterada a cada vez que uma peça sofrer alteração de preço ou uma nova peça com um preço diferente começar a ser vendida. Nessa nova implementação, foi utilizando um switch implícito também conhecido como dynamic binding. Como mostrado nesse código, nesse tipo de implementação, existirão ainda cases para a obtenção dos preços, mas, eles serão especificados diretamente nas classes que calculam o preço de cada peça.

Podemos concluir que devemos utilizar o princípio do aberto/fechado para que sempre que precisarmos estender um comportamento de uma classe, seja criado um novo código em vez de alterar o código já existente. Assim, diminuímos o grau de acoplamento, já que quando uma classe estende o comportamento de outra sem alterá-lo, essas classes ficam mais independentes e as alterações realizadas em uma delas não afetarão fortemente a outra. É como mostramos no exemplo com a solução do problema. Caso haja alteração somente no preço de uma MotherBoard, não será necessário alterar a classe Part.&nbsp; Diminuímos também os custos de manutenção já que, como as classes não estarão fortemente acopladas, ao realizar uma alteração em um método de uma delas, não será necessário alterar a(s) outra(s).

Referência:

MEYER, B. Object-Oriented Software Construction. 2. ed. New Jersey: Prentice Hall, 1997.