2011-09-19 76 views
6

根据这本书:工厂方法设计模式

工厂模式的本质是“定义一个接口 创建对象,但是让子类决定哪个类 实例化的工厂方法使一个类的实例化延迟到子类

说我有一个造物主类:

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

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

好吧,这是我的创造者类,但我不明白

工厂方法使一个类的实例化延迟到子类

它有什么用子呢? 我该用什么子类?

任何人都可以举一些例子吗?

回答

9

您的Creator班是工厂。我们将其称为ProductFactory,以便使示例更加明确。

(我假设你使用的是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(); 
     [...] 
    } 
    } 
} 

这样称呼它:

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 

因此,要回答你的问题:

这是什么必须处理子类吗?我应该怎样使用 的子类?

工厂模式的定义是说工厂定义了一个通用的API来创建一个特定类型的实例(通常是一个接口或抽象类),但返回的实现的实际类型(因此是子类参考)是工厂的责任。在该示例中,工厂返回Product实例,其中BookComputer是有效的子类。

还有其他的成语工厂,就像在工厂和工厂的具体实现的API 接受type喜欢在我的例子,但它们加上实例的类型返回,这样:

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

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

BookProductFactory该类始终返回Book实例。

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

为了明确这一点,因为似乎有点Abstract FactoryFactory method设计模式之间的混淆,让我们看一个具体的例子:

使用抽象工厂

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; 
    } 
} 

这样使用:

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; 

使用工厂方法

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; 
    } 
} 

即使用这样的:

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

当你像我在原来的例子一样使用type鉴别,我们使用parametized factory methods - 一种知道如何创建不同类型对象的方法。但是,这可以出现在Abstract FactoryFactory Method模式中。一个简单的诀窍:如果你正在扩展你使用抽象工厂的工厂类。如果使用创建方法扩展该类,那么您正在使用工厂方法。

+0

所以,在你的代码中,ProductFactory是一个抽象工厂,make是Factory Method,对吧? – Alcott

+0

'Abstract Factory'和'Factory Method'之间的区别是它自己的一个问题:)总之,当你使用类型鉴别符时,就像我在例子中所做的那样,我们使用“参数化工厂方法” - 一种方法知道如何创建不同类型的对象。但是,这可以出现在抽象工厂或工厂方法模式中。一个简单的技巧:如果你正在扩展工厂类,你正在使用'Abstract Factory'。如果你用_factory methods_扩展这个类,那么你正在使用'Factory Methods'。如果差异还不清楚,就会对SO提出不同的问题。 –

+0

要说清楚。我的答案不是使用'工厂方法'设计模式,而是'抽象工厂'设计模式。 –

3

工厂模式仅仅意味着有一些工厂类或方法负责为您创建对象;而不是你自己实例化它们。就像汽车在工厂建成一样,所以你不必这样做。

它与子类无关,但作者可能会试图说工厂经常会根据参数返回基类的派生实现,因为该子类可能会在参数中执行您要求的操作。

例如WebRequest.Create(“http://www.example.com”)会返回我HttpWebRequest,但WebRequest.Create(“ftp://www.example.com”)会返回我FtpWebRequest,因为两者都有不同的协议由不同的类实现,但公共接口是相同的,所以这个决定不必由我的API的消费者来做。

1

产品Make()将根据特定条件使产品的正确类型(子类)和“推迟”到特定产品的实际实例。

(伪码)

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; } 

厂隐藏用于构成各种产品类型所需要的条件的信息。其次,从API用户的角度来看,恕我直言,通常更容易看到哪些产品类型(通常来自枚举),更容易从单一创建点创建它们。

+0

这是否意味着一个工厂方法可能会产生(返回)几个产品,但是在工厂方法中创建哪一个产品方法和返回是根据某些条件(例如传递给工厂方法的参数)决定的。 – Alcott

+0

@Alcott请参阅我的答案中添加一些更多详细信息。 – Jake

0

我只能假设他的意思是:

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 

然而,这不是创建一个工厂的标准方法。

+0

那么什么是std的方式? – Alcott

+0

根据返回类型具有不同的方法名称,或者如Jake指出的那样指定对象类型。 –

0

在伪代码中提供这样的示例有点令人困惑,该模式非常依赖语言。您的示例看起来像使用C++,但它在C++中无效,因为make按值返回Product。这完全违背了Factory的主要目标 - 将引用(C++中的指针)返回给基类。有些答案认为C++或Java(我猜)当其他人作为C++时。

Factory模式依赖于多态性。关键是要返回基类Product类的参考。 Factory的子女将创建具体类的实例。

0

我有同样的疑惑“让子类决定实例化哪个类” - 因为在实现工厂方法中使用new来创建一个对象“ - 我参考了头部第一个设计模式书,其中清楚地陈述了如下 - “正如在官方定义中,您会经常听到开发人员说让子类决定实例化哪个类。他们说”决定“不是因为该模式允许子类自己决定运行时,而是因为创建者类不是用知识编写的的实际产品,这完全取决于所使用的子类的选择“

0

简而言之:

工厂,检查其“子”请求来实例化这样"let the subclasses decide which class to instantiate"
您使用在工厂类如果确定要作出条件语句。

"define an interface or abstract class for creating an object"。显然,你将对象存储到接口的引用中,客户端并不知道哪个具体类的对象被返回。 (所以你定义了一个接口来创建一个对象)。