Files
java-design-patterns/localization/es/abstract-factory
Luis Mateo Hincapié Martinez dc7495e8bd translation: Translated all creational patterns category to Spanish (Task of issue #2277) (#2813)
* Typo corrections

* bridge pattern translated to spanish

* builder pattern translated to spanish

* context-object pattern translated to spanish

* converter pattern translated to spanish

* dependency injection pattern translated to spanish

* factory pattern translated to spanish

* factory-kit pattern translated to spanish

* factory-method pattern translated to spanish

* monostate pattern translated to spanish

* multiton pattern translated to spanish

* object mother pattern translated to spanish

* object pool pattern translated to spanish

* property pattern translated to spanish

* prototype pattern translated to spanish

* registry pattern translated to spanish

* step builder pattern translated to spanish

* value object pattern translated to spanish

* typo corrections and resources urls refactor

* grammar corrections

* Add image to each pattern

---------

Co-authored-by: luismateoh <luismateohm@gmail.com>
Co-authored-by: luis.hincapie <luis.hincapie@blankfactor.com>
2024-03-23 11:53:54 +02:00
..

title, category, language, tag
title category language tag
Abstract Factory Creational es
Gang of Four

También conocido como

Kit

Propósito

Proveer de una interfaz para crear familias de objetos relacionados dependientes sin especificar su clase concreta.

Explicación

Ejemplo del mundo real

Para crear un reino necesitamos objetos con una temática común. El reino élfico necesita un rey elfo, un castillo élfico y un ejército élfico mientras que el reino orco necesita un rey orco, un castillo orco y un ejército orco. Hay una dependencia entre los objetos del reino.

Dicho de otra forma

Una factoría de factorías; una factoría que agrupa otras factorías individuales pero relacionadas/dependientes sin especificar su clase concreta.

Según Wikipedia

El patrón abstract factory provee una forma de encapsular un grupo de factorías individuales que tienen una temática común sin especificar sus clases concretas.

Ejemplo Programático

Traduciendo el ejemplo anterior sobre los reinos. Primero tenemos algunas interfaces e implementaciones de los objetos del Castle.

public interface Castle {
  String getDescription();
}

public interface King {
  String getDescription();
}

public interface Army {
  String getDescription();
}

// Elven implementations ->
public class ElfCastle implements Castle {
  static final String DESCRIPTION = "This is the elven castle!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfKing implements King {
  static final String DESCRIPTION = "This is the elven king!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfArmy implements Army {
  static final String DESCRIPTION = "This is the elven Army!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

// Orcish implementations similarly -> ...

Luego tenemos la abstracción e implementación de la factoría del reino KingdomFactory.

public interface KingdomFactory {
  Castle createCastle();
  King createKing();
  Army createArmy();
}

public class ElfKingdomFactory implements KingdomFactory {

  @Override
  public Castle createCastle() {
    return new ElfCastle();
  }

  @Override
  public King createKing() {
    return new ElfKing();
  }

  @Override
  public Army createArmy() {
    return new ElfArmy();
  }
}

public class OrcKingdomFactory implements KingdomFactory {

  @Override
  public Castle createCastle() {
    return new OrcCastle();
  }

  @Override
  public King createKing() {
    return new OrcKing();
  }
  
  @Override
  public Army createArmy() {
    return new OrcArmy();
  }
}

Ahora tenemos la factoría abstracta que nos permite hacer familias de objetos relacionados por ejemplo la factoría del reino élfico ElfKingdomFactory crea el castillo castle, rey king y ejército army etc.

var factory = new ElfKingdomFactory();
var castle = factory.createCastle();
var king = factory.createKing();
var army = factory.createArmy();

castle.getDescription();
king.getDescription();
army.getDescription();

Salida del programa:

This is the elven castle!
This is the elven king!
This is the elven Army!

Ahora podemos diseñar una factoría para nuestras factorías de reinos. En este ejemplo creamos FactoryMaker, responsable de devolver una instancia de ElfKingdomFactory o OrcKingdomFactory.
El cliente puede usar FactoryMaker para crear una factoría concreta, que a su vez, producirá diferentes objetos concretos (derivados de Army, King, Castle).
En este ejemplo también usamos un enum para parametrizar el tipo de factoría de reinos pedirá el cliente.

public static class FactoryMaker {

    public enum KingdomType {
        ELF, ORC
    }

    public static KingdomFactory makeFactory(KingdomType type) {
        return switch (type) {
            case ELF -> new ElfKingdomFactory();
            case ORC -> new OrcKingdomFactory();
            default -> throw new IllegalArgumentException("KingdomType not supported.");
        };
    }
}

    public static void main(String[] args) {
        var app = new App();

        LOGGER.info("Elf Kingdom");
        app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
        LOGGER.info(app.getArmy().getDescription());
        LOGGER.info(app.getCastle().getDescription());
        LOGGER.info(app.getKing().getDescription());

        LOGGER.info("Orc Kingdom");
        app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
        --similar use of the orc factory
    }

Diagrama de clases

alt text

Aplicación

Usar el patrón Abstract Factory cuando

  • El sistema debe ser agnóstico a como se crean, componen y representan sus objetos.
  • El sistema debe ser configurado con una de las múltiples familias de productos.
  • La familia de objetos relacionados está diseñada para ser usada en conjunto y necesitas forzar esta premisa.
  • Quieres proveer de una librería de productos y solo quieres revelar sus interfaces, no su implementación.
  • El tiempo de vida de la dependencia es conceptualmente más corto que el del cliente.
  • Necesitas un valor en tiempo de ejecución para construir una dependencia.
  • Quieres decidir que producto de una familia llamar en tiempo de ejecución.
  • Necesitas proveer de uno o más parámetros solo conocidos en tiempo de ejecución antes de poder resolver la dependencia.
  • Necesitas consistencia entre productos.
  • No quieres cambiar el código existente al añadir nuevos productos o familias de productos al programa.

Ejemplos de casos de uso

  • Elegir llamar a la implementación correcta de FileSystemAcmeService o DatabaseAcmeService o NetworkAcmeService en tiempo de ejecución.
  • Escribir test unitarios se hace mucho más sencillo.
  • Herramientas UI (User Interface) para diferentes SO (Sistemas Operativos).

Consecuencias

  • La inyección de dependencias en java esconde las dependencias de la clase servicio lo que puede llevar a errores de ejecución que se podrían haber evitado al compilar.
  • Mientras que el patrón es muy bueno creando objetos predefinidos, añadir nuevos puede ser complicado.
  • El código es más complicado de lo que debería porque se añaden muchas interfaces y clases nuevas junto con el patrón.

Tutoriales

Usos conocidos

Patrones relacionados

Créditos