2011-09-19 15 views
6

Según el libro:.fábrica patrón de diseño método

La esencia del patrón de fábrica es "Definir una interfaz para crear un objeto, sino dejar que las subclases decidir qué clase de una instancia del método de fábrica permite una ejemplificación Defer clase para subclases

Decir que tengo una clase Creador:.

class Product; //this is what the Factory Method should return 
class Creator { 
    public: 
     Creator() //ctor 
     { //... } 

     virtual Product make(//args) 
     { //... } 
} 

Ok, eso es mi clase Creador, pero no entiendo

El método de fábrica permite aplazar una instanciación de la clase a las subclases

¿Qué tiene que ver con las subclases? ¿Y para qué se supone que debo usar las subclases?

¿Alguien me puede dar un ejemplo?

Respuesta

9

Su Creator clase es la fábrica. Vamos a llamarlo ProductFactory, para hacer el ejemplo más explícito.

(estoy asumiendo que usted está utilizando C++)

class Book : public Product 
{ 
}; 

class Computer : public Product 
{ 
}; 

class ProductFactory 
{ 
public: 
    virtual Product* Make(int type) 
    { 
    switch (type) 
    { 
     case 0: 
     return new Book(); 
     case 1: 
     return new Computer(); 
     [...] 
    } 
    } 
} 

llamada así:

ProductFactory factory = ....; 
Product* p1 = factory.Make(0); // p1 is a Book* 
Product* p2 = factory.Make(1); // p2 is a Computer* 
// remember to delete p1 and p2 

lo tanto, para responder a su pregunta:

Lo que lo hace tiene que ver con las subclases? ¿Y para qué se supone que debo usar las subclases ?

cuál es la definición de patrón de la fábrica está diciendo es que la fábrica define una API común para la creación de instancias de un tipo determinado (normalmente una interfaz o clase abstracta), pero el tipo real de las implementaciones volvió (por lo tanto la subclase referencia) es responsabilidad de la fábrica. En el ejemplo, la fábrica devuelve instancias Product, para las cuales Book y Computer son subclases válidas.

Existen otras expresiones idiomáticas para la fábrica, como tener una API para la fábrica y las implementaciones concretas de la fábrica no aceptar una type como en mi ejemplo, pero que están acoplados con el tipo de instancias volvió, como este :

class ProductFactory 
{ 
public: 
    virtual Product* Make() = 0; 
} 

class BookProductFactory : public ProductFactory 
{ 
public: 
    virtual Product* Make() 
    { 
     return new Book(); 
    } 
} 

En esta clase BookProductFactory siempre devuelve Book casos.

ProductFactory* factory = new BookProductFactory(); 
Product* p1 = factory->Make(); // p1 is a Book 
delete p1; 
delete factory; 

Para que quede claro, ya que parece que hay un poco de confusión entre Abstract Factory y Factory method patrones de diseño, vamos a ver un ejemplo concreto:

Usando Abstract Factory

class ProductFactory { 
protected: 
    virtual Product* MakeBook() = 0; 
    virtual Product* MakeComputer() = 0; 
} 

class Store { 
public: 
    Gift* MakeGift(ProductFactory* factory) { 
    Product* p1 = factory->MakeBook(); 
    Product* p2 = factory->MakeComputer(); 
    return new Gift(p1, p2); 
    } 
} 

class StoreProductFactory : public ProductFactory { 
protected: 
    virtual Product* MakeBook() { return new Book(); } 
    virtual Product* MakeComputer() { return new Computer(); } 
} 

class FreeBooksStoreProductFactory : public StoreProductFactory { 
protected: 
    virtual Product* MakeBook() { 
    Book* b = new FreeBook(); // a FreeBook is a Book with price 0 
    return b; 
    } 
} 

Eso se usa así:

Store store; 
ProductFactory* factory = new FreeBooksStoreProductFactory(); 
Gift* gift = factory->MakeGift(factory); 
// gift has a FreeBook (Book with price 0) and a Computer 
delete gift; 
delete factory; 

Utilizando el método de fábrica

class Store { 
public: 
    Gift* MakeGift() { 
    Product* p1 = MakeBook(); 
    Product* p2 = MakeComputer(); 
    return new Gift(p1, p2); 
    } 

protected: 
    virtual Product* MakeBook() { 
    return new Book(); 
    } 

    virtual Product* MakeComputer() { 
    return new Computer(); 
    } 
} 

class FreeBooksStore : public Store { 
protected: 
    virtual Product* MakeBook() { 
    Book* b = new FreeBook(); // a FreeBook is a Book with price 0 
    return b; 
    } 
} 

que se utiliza como esto:

Store* store = new FreeBooksStore(); 
Gift* gift = store->MakeGift(); 
// gift has a FreeBook (Book with price 0) and a Computer 
delete gift; 
delete store; 

Cuando se utiliza un discriminador type como lo hice en el ejemplo original, estamos utilizando parametized factory methods - un método que sabe cómo crear diferentes tipos de objetos. Pero eso puede aparecer en un patrón Abstract Factory o Factory Method. Un pequeño truco: si está ampliando la clase de fábrica, está utilizando Abstract Factory. Si amplía la clase con los métodos de creación, entonces está utilizando métodos de fábrica.

+0

entonces, en su código, ProductFactory es una fábrica abstracta, y make es el método de fábrica, ¿no? – Alcott

+0

La diferencia entre 'Abstract Factory' y' Factory Method' sería una pregunta por sí misma. En resumen, cuando usa un discriminador de tipo como lo hice en el ejemplo, estamos usando "métodos de fábrica parametrizados", un método que sabe cómo crear diferentes tipos de objetos. Pero eso puede aparecer en un patrón Abstract Factory o Factory Method. Un pequeño truco: si está ampliando la clase de fábrica, está utilizando 'Abstract Factory'. Si amplía la clase con _factory methods_, entonces está utilizando 'Factory Methods'. Si la diferencia aún no está clara, plantee una pregunta diferente sobre SO. –

+0

Para dejarlo en claro. Mi respuesta no utiliza el patrón de diseño 'Método de fábrica' sino el patrón de diseño' Fábrica abstracta'. –

3

El patrón de fábrica simplemente significa que hay alguna clase o método de fábrica cuya responsabilidad es crear objetos para usted; en lugar de ejemplificarlos tú mismo. Al igual que los autos se construyen en las fábricas, no es necesario.

No tiene nada que ver con las subclases; sin embargo, el autor podría intentar decir que la fábrica puede devolverle la implementación derivada de una clase base basada en sus parámetros porque esa subclase puede hacer lo que está pidiendo en los parámetros.

Por ejemplo WebRequest.Create ("http://www.example.com") me devolvería HttpWebRequest pero WebRequest.Create ("ftp://www.example.com") me devolvería FtpWebRequest porque ambos tienen diferentes protocolos implementados por diferentes clases, pero la interfaz pública es la misma, por lo tanto, esta decisión no debe tomarla el consumidor de mi API.

1

El producto Make() hará el tipo correcto (subclase) de producto según ciertas condiciones y "diferirá" la instanciación real de los productos específicos.

(pseudo código)

public class Product 
{ 
    public static Product Make() 
    { 
     switch(day_of_week) 
     { 
      case Monday: return new Honey(1.1); 
      case Wednesday: return new Milk(3.6); 
      case Thurday: return new Meat(0.5); 
      case Friday: return new Vegetable(1.3); 
      case Saturday: return new Vegetable(2.3); // more expensive on saturday, only factory need to know 
      default: return null; // off day! 
     } 
    } 

    // returns price based on underlying product type and hidden/auto conditions (days of week) 
    public virtual void GetPrice() { return Price; } 

    // sometimes a factory can accept a product type enum 
    // From API POV, this is easier at a glance to know avaliable types. 
    pubic enum Type { Milk, Honey, Meat, Vegetable }; 

    public static Product Make(Type, Day) 
    { 
     // create the specified type for the specified day. 
    } 
} 

public class Honey : Product { Price = arg; } 
public class Milk : Product { Price = arg; } 
public class Meat : Product { Price = arg; } 
public class Vegetable : Product { Price = arg; } 

fábrica oculta los detalles condicionales requeridas para la construcción de los distintos tipos de productos. En segundo lugar, en mi humilde opinión, desde el punto de vista del usuario API, generalmente es más fácil ver qué tipos de productos hay (generalmente de una enumeración) y es más fácil crearlos desde un único punto de creación.

+0

significa que un método de fábrica puede producir (devolver) varios productos, pero cuál crear dentro del método de fábrica y devolver depende de algunas condiciones (como los args pasados ​​al método de fábrica). – Alcott

+0

@Alcott, por favor, ver más detalles agregados a mi respuesta. – Jake

0

sólo puedo suponer que esto significa:

class Product; //this is what the Factory Method should return 
class Box : Product; 

class Creator { 
    public: 
     Creator() //ctor 
     { //... } 

     virtual Product* make(//args) = 0; 
}; 

class BoxCreator{ 
    public: 
     BoxCreator() 
     {} 
     virtual Product* make() 
     {} 
}; 

Creator* pCreator = new BoxCreator; 
Product* pProduct = pCreator->make(); //will create a new box 

Sin embargo, esto no es una forma estándar para crear una fábrica.

+0

entonces, ¿cuál es la forma más común? – Alcott

+0

teniendo diferentes nombres de método según el tipo de devolución, o, como señaló Jake, especificando el tipo de objeto. –

0

Proporcionar tales ejemplos en pseudocódigo es un poco confuso, el patrón depende en gran medida del idioma. Su ejemplo se parece a C++, pero no es válido en C++ porque make devuelve Product por valor.Esto está completamente en contra del objetivo principal de Factory - para devolver una referencia (puntero en caso C++) a la clase base. Algunas respuestas toman esto como C# o Java (supongo) cuando otros como C++.

Factory patrón se basa en el polimorfismo. El punto clave es devolver una referencia a la clase base Product. Los niños de Factory crearán instancias de clases concretas.

0

Tengo la misma confusión "deja que las subclases decidan qué clase instanciar" -Me refiero al método de fábrica de implementación usando nuevo para crear un objeto "- Remito el primer libro de patrones de diseño de Head en el que se expresa claramente de la siguiente manera: "Como en la definición oficial, a menudo los desarrolladores dicen que la subclase decide qué clase instanciar. Decir" decide "no porque el patrón permita que la subclase decida el tiempo de ejecución, sino porque la clase creadora está escrita sin conocimiento del producto real que se creará, que se decide puramente por la elección de la subclase que se utiliza "

0

simple y corto:

En el fábrica, se comprueba la que "subclase" se solicita para crear una instancia de modo "let the subclasses decide which class to instantiate"
(utilice sentencias condicionales en clase de fábrica, donde la decisión tiene que ser hecho.)

"define an interface or abstract class for creating an object". obviamente, usted almacena el objeto en la referencia de la interfaz y el cliente no sabe qué objeto de la clase concreta se devuelve. (Entonces definiste una interfaz para crear un objeto).

Cuestiones relacionadas