Directrices concisas para aplanar la herencia
Siga varias directrices concisas para aplanar la herencia.
- Para cada clase de la jerarquía de tipos, cambie el nombre de la clase de
[Name]a[Name]Impl. - Extraiga una interfaz de cada una de estas clases, proporcionando cada uno de los nombres originales utilizados para dichas clases. Incluya todos los métodos públicos y los campos estáticos constantes en cada interfaz.
- Cree una jerarquía de tipos a través de las interfaces extraídas que sea idéntica al conjunto original de clases. Por ejemplo, si
BImplamplíaAImpl,BamplíaA. - Copie los métodos y campos de cada clase padre a sus hijos inmediatos. Repita recursivamente a lo largo de toda la jerarquía de tipos.
- Resuelva los conflictos de denominación para métodos alterados temporalmente o campos sombreados cambiando el nombre de los métodos y campos que se han copiado de la clase padre.
- Sustituya las llamadas a
super.method()llamando directamente a los métodos que se han convertido en la clase plana. - Resuelva los errores de los superconstructores copiados de forma similar a los pasos 5 y 6.
- Elimine las extensiones de tipo de las clases de implementación (es decir, si
BImplamplíaAImpl, elimineextends AImpl) para eliminar la herencia. - (Opcional) Suprima el código inactivo, las clases abstractas o cualquier clase o método al que ya no se haga referencia.
Como ejemplo sencillo de aplanar la herencia, tenga en cuenta la siguiente jerarquía de clases.
public class Bird {
private String description;
public void setDecription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
public class Bluejay extends Bird {
public String getName() {
return "Bluejay";
}
}
public class Cardinal extends Bird {
public String getName() {
return "Cardinal";
}
}
Al aplicar estas directrices para aplanar la herencia, se genera este conjunto de interfaces:
public interface Bird {
public void setDecription(String description);
public String getDescription();
}
public interface Bluejay extends Bird {
public String getName();
}
public interface Cardinal extends Bird {
public String getName();
}
Además, se genera una clase de implementación para cada una de estas interfaces:
public class BirdImpl implements Bird {
private String description;
public void setDecription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
public class BluejayImpl implements Bluejay {
private String description;
public void setDecription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public String getName() {
return "Bluejay";
}
}
public class CardinalImpl implements Cardinal {
private String description;
public void setDecription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public String getName() {
return "Cardinal";
}
}
Como resultado, se mantiene la jerarquía de tipos original y se elimina la herencia. Esta arquitectura permite que la generación de código para las clases refactorizadas se distribuya entre particiones.
Como alternativa a la copia de métodos y campos de la clase padre, el aplanado todavía se puede lograr mediante delegación cambiando la relación de las clases de extensión a contención. Por ejemplo, las clases BluejayImpl y CardinalImpl se cambiarían para tener una instancia de BirdImpl y, a continuación, delegarían las llamadas a sus métodos.
public class BluejayImpl implements Bluejay {
private Bird bird = new BirdImpl();
public void setDecription(String description) {
bird.setDecription(description);
}
public String getDescription() {
return bird.getDescription();
}
public String getName() {
return "Bluejay";
}
}
public class CardinalImpl implements Cardinal {
private Bird bird = new BirdImpl();
public void setDecription(String description) {
bird.setDecription(description);
}
public String getDescription() {
return bird.getDescription();
}
public String getName() {
return "Cardinal";
}
}