Factory Method (patrón de deseño)

Na Galipedia, a Wikipedia en galego.

Factory Method é un patrón de deseño do tipo creacional que se emprega para implementar o concepto de fábrica.

Este patrón trata co problema de crear obxectos (produtos) sen especificar a clase exacta á que pertencen os obxectos que van a ser creados.

A esencia do patrón é a de "Definir unha interface para crear obxectos pero deixar que sexan as subclases as que decidan que clases instanciar. Permitindo que unha clase delegue nas súas subclases a creación de obxectos".

A creación de un obxecto, a miúdo require procesos demasiado complexos para incluír nos obxectos que os desexan crear. A creación de obxectos complexos pode levar a unha replicación excesiva de código, requirir información que non é accesible dende o obxecto creador, ou non proveer un nivel de abstracción suficiente.

Aplicabilidade[editar | editar a fonte]

Este patrón é recomendable cando se dan algunha das seguintes condicións:

  1. A creación de un obxecto impide a súa reutilización sen unha duplicación significativa de código.
  2. A creación de un obxecto precisa acceso acceso a información ou recursos que non deben ser accesibles dende a clase creadora.
  3. A xestión do tempo de vida dos obxectos xerados debe ser centralizada para asegurar un comportamento consistente do aplicativo.

Os métodos de fabrica son comúns en "Frameworks" e "Toolkits", onde o código da biblioteca precisa crear obxectos de tipos que poden ser redefinidos polas aplicacións que están a usar o Framework.

Os métodos factoría tamén son usados comunmente no desenvolvemento dirixido por probas. Por exemplo, se unha clase crea un tipo de obxecto que non se pode incluír nunha proba unitaria, pódese redefinir o método da factoría para que devolva un obxecto falso que sirva para realizar as probas.

Estrutura[editar | editar a fonte]

  • Produto: define a interface dos obxectos creados polo método de fabricación.
  • Produto concreto: implementa a interface dos produtos.
  • Creador: declara o método de fabricación que devolverá un obxecto produto. Adicionalmente, se o creador desexa pode definir unha implementación por defecto que constrúe un produto concreto.
  • Creador concreto: redefine o método de fabricación para devolver unha instancia dun produto concreto.
Diagrama de clases do método fábrica.

Limitacións[editar | editar a fonte]

Existen tres importantes limitacións á hora de usar o patrón método factoría. O primeiro, relacionado con refactorizar o código existente, e os outros dous, relacionados con estender unha clase xa existente.

  1. A primeira limitación, é que refactorizar unha clase para que comece a usar un método factoría, rompe a compatibilidade cos clientes actuais. Por exemplo se temos unha clase Complexo, que se usa da maneira habitual, sen factorías, pode haber múltiples clientes que usen un código similar a:
    Complexo c1 = new Complexo(1,0);
    
    Unha vez que decidimos que para a clase Complexo precisamos un ou máis métodos fabrica, o construtor pasaría a ser privado, co que o código dos clientes non sería correcto.
  2. A segunda limitación, é que dado que o patrón se basa en que a clase debe ter o construtor privado, a clase non pode ser estendida, xa que para estender unha clase débese ter acceso, ao construtor da superclase.
  3. A terceira limitación é que se estendemos a clase, por exemplo facendo o construtor protexido, a subclase pode proveer as súas propias reimplementacións dos métodos factorías coas mesmas firmas.

Colaboracións[editar | editar a fonte]

O creador emprega o método de fabricación redefinido polas súas subclases para utilizar a instancia de produto concreto.

Consecuencias favorables
  1. A principal consecuencia positiva é que elimina a necesidade de incluír clases específicas da aplicación no código xeral.
  2. Aporta unha maior flexibilidade.
  3. Conecta xerarquías de clases paralelas.
Consecuencias desfavorables
  1. Pode darse o caso no que sexa mellor o uso doutro tipo de patróns como por exemplo o prototipo, xa que o método de fabricación pode obrigar a estender a clase creadora para crear un produto concreto.
Implementación

Existen dúas variantes, unha na que o creador é unha clase abstracta e non aporta unha implementación por defecto, e outra variante na que o creador é unha clase concreta polo que define un produto concreto por defecto. No primeiro caso será preciso estender o creador, mentres que se optamos pola outra posible implementación estaremos gañando maior flexibilidade para posibles cambios futuros.

Exemplo de colaboración

A continuación amósase un diagrama de secuencia no que se pode ver un exemplo das colaboracións típicas involucradas neste patrón.

SecuenciaMetodoFact

Outros beneficios e variantes[editar | editar a fonte]

Aínda que a principal motivación que se persigue mediante o uso do patrón método de factoría é o de permitir que sexan as subclases as que decidan que tipo de obxectos crear, o uso do mesmo ten outras vantaxes asociadas, moitas das ccakes non dependen de crear novas subclases. Como consecuencia, é común crear métodos factoría que non sexan polimorficos para a creación de obxectos para conseguir eses outros beneficios. Eses métodos, a miúdo son estáticos.

Nomes descritivos[editar | editar a fonte]

Un método factoría pode ter o nome que mais conveña, mentres que na maioría das linguaxes orientadas a obxectos , o construtor soamente se pode chamar do mesmo modo que a clase no que son definidos, o cal pode leva a ambigüidades no caso de que existas múltiples maneiras de crear un obxecto.

Os métodos fábrica non teñen esa restrición e pódese adaptar o nome que máis lle conveña ao método.

Como exemplo, cando os números complexos son creados a partir de dous números enteiros, eses dous números, poden ser coordenadas polares ou cartesianas, o que nos leva a unha ambigüidade. Sen embargo usando métodos factoría esta é solventada como se pode ver no seguinte exemplo.

Java[editar | editar a fonte]

    public class Complexo
    {
        public double real;
        public double imaxinario;
 
        public static Complexo fabricaCartesiana(double real, double imaxinario)
        {
            return new Complexo(real, imaxinario);
        }
 
        public static Complexo fabricaPolar(double modulo, double angulo)
        {
            return new Complexo(modulo * Math.cos(angulo), modulo * Math.sin(angulo));
        }
 
        private Complexo(double real, double imaxinario)
        {
            this.real = real;
            this.imaginary = imaxinario;
        }
    }
class Cliente{
   public static void main(String args){
      Complexo producto1 = Complexo.fabricaCartesiana(1,Math.PI); 
   }
}

Encapsulación[editar | editar a fonte]

Os métodos fábrica, encapsulan a creación de obxectos. Isto pode ser útil se o proceso de creación é moi complexo, por exemplo, cando dependen de ficheiros de configuración ou da interacción do usuario.

Considérese como exemplo un aplicativo que lee ficheiros de imaxe. O programa ten a capacidade de ler diferentes tipos de imaxe, representado por unha clase lectora para cada un dos formatos. Cada vez que o programa lé unha nova imaxe, ten que instanciar un lector para o formato de imaxe apropiado, baseándose na información do ficheiro. Esta lóxica pode ser encapsulada dentro de un método de fabrica.

Java[editar | editar a fonte]

public class FabricaLectorImaxes {
    public static LectorImaxes metrodoFabricaLectorImaxes(ImageInputStreamProcessor iisp) {
        LectorImaxes producto = null;
 
        if( iisp.eGIF() ) {
          product = new LectorGif(iisp.getInputStream());
        }
        else if( iisp.eJPEG() ) {
          product = new LectorJpeg(iisp.getInputStream());
        }
        else {
          throw new IllegalArgumentException( "Tipo de imaxe edscoñecido" );
        }
 
        return producto;
    }
}


Véxase tamén[editar | editar a fonte]

Ligazóns externas[editar | editar a fonte]