Uso de Polimorfismo De Inclusão
Autor: Kênia | Publicado: 2017-08-27T22:00:00-03:00





Assunto abordado por Cardelli (1985), o polimorfismo de inclusão é o polimorfismo que decorre do mecanismo de herança também conhecido como é-um e subtipos. A questão ser observada é a implementação correta do contrato da classe em todas as suas subclasses e se os campos estão sendo tratados de forma consistente. É necessário verificar ainda se as informações estão distribuídas corretamente ao longo da hierarquia. Itens usados de forma geral devem estar na superclasse e itens particulares, nas subclasses. Os subtipos devem ser aceitos onde os tipos forem esperados.

Veja o exemplo da implementação a seguir de um sistema de guarda de veículos em uma garagem. Nele observamos problemas como inconsistência no uso do campo plate por algumas operações e a operação identify que poderia ter sua implementação realizada de uma forma mais geral:

//Classe Veículo
class Vehicle {
protected String plate;
public vehicle(){ };
public Vehicle(String p){
plate = p;
}
public String identify(){
return "generic vehicle";
}
}

//Classe Carro, subclasse de Veículo
class Car extends Vehicle {
public Car(){super();}
public Car(String p){super(p);}
public String identify {
return "car with plate" + plate;
}
}

//Classe Caminhão, sublcasse de veículo
class Truck extends Vehicle {
public Truck() { super(); }
public Truck(String p) {super(p);}
public String identify( ){
return "truck with plate " + plate;
}
}

//Classe Garagem
class Garage {
private int maxVehicles;
private Vehicle[ ] parked;
public Garage(int max) {
maxVehicles = (max &lt; 1)? 1 : max;
parked = new Vehicle[maxVehicles];
}
&nbsp;&nbsp;&nbsp; 
//Preencher vaga
public int accept(Vehicle v) {
for(int bay = 0; bay&lt;maxVehicles; ++bay )
if (parked[bay] = null) {
parked[bay] = v; return bay;
}
return -1; // no bay available;
}
//Devolver o veículo e liberar a vaga
public Vehicle release(int bay){
if (bay&lt;0 || bay&gt;=maxVehicles)return null;
Vehicle v = parked[bay];
parked[bay] = null;
return v;
} 

//Listar veículos estacionados na garagem
public void listVehicles(){
for(int bay = 0; bay &lt; maxVehicles; ++bay)
if( parked[bay] != null ) {
System.out.println ("Vehicle in bay " + bay + "is " 
parked[bay].identify());
}
}

//Um dia na garagem
public static void main(String[ ] args){
Garage park(15);

//Veículos em operação
Vehicle c1 = new Car("RVR 101");
Vehicle c2 = new Car("SPT 202");
Vehicle c3 = new Car("CHP 303");
Vehicle c4 = new Car("BDY 404");
Vehicle c5 = new Car("BCH 505");

Vehicle t1 = new Truck("TBL 606");
Vehicle t2 = new Truck("IKY 707");
Vehicle t3 = new Truck("FFY 808");
Vehicle t4 = new Truck("PCS 909");
Vehicle t5 = new Truck("SLY 000");

park.accept(c1);
int t2bay = park.accept(t2);
Park.accept(c3); park.accept(t1);
int c4bay = park.accept(c4);
park.accept(c5); park.accept(t5);
park.release(t2bay);
park.accept(t4); park.accept(t3);
park.release(c4bay); park.accept(c2);
park.listVehicles();
}

}

Ao analisar separadamente as seguintes partes do código dado, vamos identificar o problema da implementação:

//As construtoras iniciam plate com null:
public Vehicle( ) { }
public Car( ) extends Vehicle( ) { }
public Truck( ) extends Vehicle( ) { }

//As seguintes operações supõem que plate não poderia ser null
public String identify() { //identify de Car
return “car with plate " + plate;
}
public String identify( ){ //identify de Truck
return "truck with plate " + plate; 
}

Verifique a solução do problema com as operações corrigidas. Agora elas inicializam o campo antes de imprimir:

public String identify() { //identify de Car
String p = plate? plate : “&lt;none&gt;”;
return "car with plate " + p);
}

public String identify( ){ //identify de Truck
String p = plate? plate : “&lt;none&gt;”;
return "truck with plate “ + p);
}

Ainda verificando problemas nessa implementação de polimorfismo. Podemos ver na organização da hierarquia que a operação idenfify é utilizada de forma quase idêntica pelas duas subclasses. A única alteração nelas é que uma imprime “car” e a outra “truck” em seus textos de identificação. Esta operação então deve ser feita na superclasse e simplificada nas subclasses. 

Vamos então, mover identify para superclasse e verificar a nova versão das classes Vehicle, Car e Truck no sistema de garagem:

//Classe veículo
class Vehicle {
private String plate;
private String group;
public Vehicle(string g, String p){
group = g; p = plate;
}
public Vehicle(string g){this(g,null);}
public String identify( ){
String p = plate? plate : "&lt;none&gt;";
return group + " with plate " + p;
}
}

//Classe Carro, subclasse de Veículo
class Car extends Vehicle {
public Car(String p){super("car", p);}
public Car( ){this(null);}
}

//Classe Caminhão, subclasse de Veículo
class Truck extends Vehicle {
public Truck(String p){super(“truck",p);}
public Truck( ){this(null);}
}

Referência:

CARDELLI, L.; WEGNER, P. On understanding types, data abstractions andpolimorphism, ACM Computing Surveys, 17, 451-522. 1985. Disponível em 
&lt; http://lucacardelli.name/papers/onunderstanding.a4.pdf&gt;. Acesso em: 24 jan.2016.