工厂方法设计模式

时间:2011-09-19 08:19:05

标签: design-patterns factory-method

根据这本书:

  

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

说我有一个创作者课程:

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

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

好的,那是我的创作者课程,但我不明白

  

Factory方法允许类将实例化延迟到子类

它与子类有什么关系? 我应该使用什么子类?

任何人都能给我一些例子吗?

8 个答案:

答案 0 :(得分:10)

您的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模式显示。一个简单的技巧:如果您正在扩展工厂类,那么您正在使用Abstract Factory。如果使用创建方法扩展类,则使用工厂方法。

答案 1 :(得分:3)

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

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

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

答案 2 :(得分:1)

Product 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用户的角度来看,通常更容易看到有哪些产品类型(通常来自枚举),并且更容易从单一创建点创建它们。

答案 3 :(得分:1)

简单和简短:

工厂中,检查要求哪个“子类”实例化"let the subclasses decide which class to instantiate"
您在必须做出决定的工厂类中使用条件语句。

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

答案 4 :(得分: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

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

答案 5 :(得分:0)

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

Factory模式依赖于多态性。关键点是返回对基类Product类的引用。 Factory的子项将创建具体类的实例。

答案 6 :(得分:0)

我有同样的困惑"让子类决定实例化哪个类" - 因为在实现工厂方法时使用new来创建一个对象" - 我参考Head第一个设计模式书,其中明确说明如下 - "正如在官方定义中你经常会听到开发人员说让子类决定实例化哪个类。他们说"决定"不是因为模式允许子类自己决定运行时,而是因为创建者class是在不知道将要创建的实际产品的情况下编写的,这完全取决于所使用的子类的选择"             

答案 7 :(得分:0)

Factory方法是一种创建性设计模式,它提供了一个用于在超类中创建对象的接口,但允许子类更改将要创建的对象的类型。此示例说明了如何使用Factory方法创建跨平台UI元素,而无需将客户端代码耦合到具体的UI类。

// contains some core business logic that relies on product // objects returned by the factory method. Subclasses can // indirectly change that business logic by overriding the // factory method and returning a different type of product // from it.

method render() is

// Call the factory method to create a product object. Button okButton = createButton() // Now use the product.

okButton.onClick(closeDialog) okButton.render()

// Concrete creators override the factory method to change the // resulting product's type.

class WindowsDialog extends Dialog is

method createButton():Button is return new WindowsButton()

class WebDialog extends Dialog is method createButton():Button is return new HTMLButton()

// The product interface declares the operations that all // concrete products must implement.

interface Button is

method render() method onClick(f)

// Concrete products provide various implementations of the // product interface.

class WindowsButton implements Button is method render(a, b) is // Render a button in Windows style.

is

method onClick(f) is // Bind a native OS click event.

class HTMLButton implements Button is

is

method render(a, b) is // Return an HTML representation of a button. method onClick(f) is

// Bind a web browser click event.

class Application is field dialog: Dialog

// The application picks a creator's type depending on the // current configuration or environment settings.

method initialize() is config = readApplicationConfigFile()

if (config.OS == "Windows") then dialog = new WindowsDialog() else if (config.OS == "Web") then

dialog = new WebDialog() else

throw new Exception("Error! Unknown operating system.")

// The client code works with an instance of a concrete // creator, albeit through its base interface. As long as // the client keeps working with the creator via the base // interface, you can pass it any creator's subclass.

method main() is

this.initialize() dialog.render()
相关问题