7

根据书:

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

假设我有一个 Creator 课程:

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

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

好的,这是我的 Creator 课程,但我不明白

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

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

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

4

8 回答 8

11

你的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模式出现。一个小技巧:如果你正在扩展你正在使用抽象工厂的工厂类。如果您使用创建方法扩展类,那么您使用的是工厂方法。

于 2011-09-19T08:29:05.097 回答
3

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

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

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

于 2011-09-19T08:26:04.670 回答
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 用户的角度来看,通常更容易查看有哪些产品类型(通常来自枚举),并且更容易从单个创建点创建它们。

于 2011-09-19T08:26:06.860 回答
1

简单而简短:

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

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

于 2017-09-25T13:33:25.267 回答
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

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

于 2011-09-19T08:26:41.073 回答
0

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

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

于 2011-09-19T08:39:51.677 回答
0

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

于 2015-09-23T14:42:04.220 回答
0

工厂方法是一种创建型设计模式,它提供了在超类中创建对象的接口,但允许子类更改将要创建的对象的类型。此示例说明如何使用工厂方法创建跨平台 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()
于 2020-11-07T17:21:55.693 回答