java - Usando la reflexión en el patrón de fábrica
reflection factory (3)
El propósito del patrón de fábrica es desparejar algunos códigos del tipo de tiempo de ejecución de un objeto que consume:
// This code doesn''t need to know that the factory is returning
// an object of type `com.example.parties.SurpriseParty`
AbstractParty myParty = new PartyFactory().create(...);
Al usar un código como este, PartyFactory
es el PartyFactory
responsable de determinar o saber exactamente qué tipo de tiempo de ejecución se debe usar.
Está renunciando a ese beneficio al ingresar el nombre completo de la clase que necesita. Cómo es esto...
// This code obviously DOES know that the factory is returning
// an object of type `com.example.parties.SurpriseParty`.
// Now only the compiler doesn''t know or enforce that relationship.
AbstractParty myParty = new PartyFactory().create("com.example.parties.SurpriseParty");
... diferente de simplemente declarar myParty
como de tipo com.example.parties.SurpriseParty
? Al final, su código está igual de acoplado, pero ha abandonado la verificación de tipo estático. Eso significa que está incurriendo en menos que ningún beneficio, al tiempo que renuncia a algunos de los beneficios de la fuerte tipificación de Java. Si elimina com.example.parties.SurpriseParty
su código aún se compilará, su IDE no le dará ningún mensaje de error y no se dará cuenta de que había una relación entre este código y com.example.parties.SurpriseParty
hasta el tiempo de ejecución; malo.
Como mínimo, le aconsejaría que al menos cambie este código para que el argumento del método sea un nombre de clase simple, no un nombre completamente calificado:
// I took the liberty of renaming this class and it''s only method
public class MyPartyFactory{
public Party create(String name)
{
//TODO: sanitize `name` - check it contains no `.` characters
Class c = Class.forName("com.example.parties."+name);
// I''m going to take for granted that I don''t have to explain how or why `party` shouldn''t be an instance variable.
Party party = (PersonalParty)c.newInstance();
return party;
}
}
Siguiente: ¿es una mala práctica usar Class.forName(...)
? Eso depende de cuál sea la alternativa, y la relación entre esos argumentos de String
( name
) y las clases que proporcionará esta fábrica. Si la alternativa es un gran condicional:
if("SurpriseParty".equals(name) {
return new com.example.parties.SurpriseParty();
}
else if("GoodbyeParty".equals(name)) {
return new com.example.parties.GoodbyeParty();
}
else if("PartyOfFive".equals(name)) {
return new com.example.parties.PartyOfFive();
}
else if(/* ... */) {
// ...
}
// etc, etc etc
... Eso no es escalable. Dado que existe una relación observable obvia entre los nombres de los tipos de tiempo de ejecución que esta fábrica crea y el valor del argumento del name
, debe considerar usar Class.forName
lugar. De esa manera, su objeto Factory
estará protegido de la necesidad de un cambio de código cada vez que agregue un nuevo tipo de Party
al sistema.
Algo más que podrías considerar es usar el patrón AbstractFactory
lugar. Si su código de consumo se ve así:
AbstractParty sParty = new PartyFactory().create("SurpriseParty");
AbstractParty gbParty = new PartyFactory().create("GoodByeParty");
... donde se solicita un número limitado de tipos de partes que ocurren con frecuencia, debe considerar tener diferentes métodos para esos tipos diferentes de partes:
public class PartyFactory {
public Party getSurpriseParty() { ... }
public Party getGoodByeParty() { ... }
}
... lo que le permitirá aprovechar la escritura estática de Java.
Sin embargo, esta solución significa que cada vez que agregue un nuevo tipo de Party
, tendrá que cambiar el objeto de fábrica, por lo tanto, si la solución reflectiva o el AbstractFactory
es una solución mejor, realmente depende de la frecuencia y la rapidez con la que vaya a agregar. Tipos de Party
¿Un nuevo tipo cada día? Usa la reflexión. ¿Un nuevo tipo de fiesta cada década? Utilice un AbstractFactory
.
¿Es una buena práctica usar el patrón Reflection in Factory?
public class MyObjectFactory{
private Party party;
public Party getObject(String fullyqualifiedPath)
{
Class c = Class.forName(fullyqualifiedPath);
party = (PersonalParty)c.newInstance();
return party;
}
}
Parte personal implementa fiesta
Podría usarlo para una API en la que proporcione una API y un archivo de configuración XML donde los usuarios puedan agregar los nombres de clase de su complemento. Entonces, sí, podrías usar esto
Usar la reflexión de esta manera (Class.forName) es casi siempre un signo de mal diseño de la aplicación. Existen algunos tipos, donde su uso es correcto, por ejemplo, si está realizando algún tipo de carga dinámica de bibliotecas o complementos externos.