工厂方法设计模式

发布于 2024-12-05 04:34:38 字数 505 浏览 6 评论 0原文

据书中所述:

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

假设我有一个 Creator 类:

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

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

好的,这是我的 Creator 类,但我不明白

工厂方法让类将实例化推迟到子类

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

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

According to the book:

The essence of the Factory Pattern is to "Define an interface for
creating an object, but let the subclasses decide which class to
instantiate. The Factory method lets a class defer instantiation to
subclasses.

Say I have a Creator class:

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

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

Ok, that's my Creator class, but I don't understand

The Factory method lets a class defer instantiation to subclasses

What does it have to do with subclasses?
And what am I supposed to use subclasses for?

Anyone can give me some example?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

亢潮 2024-12-12 04:34:38

您的 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,并且工厂的具体实现像我的示例中那样接受类型,但它们与返回实例的类型,如下所示:

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;

为了清楚起见,由于抽象工厂工厂方法设计模式之间似乎有点混淆,让我们看一个具体的例子:

使用抽象工厂< /strong>

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 鉴别器时,我们使用 <代码>参数化工厂方法 - 知道如何创建不同类型对象的方法。但这可以出现在抽象工厂或工厂方法模式中。一个简单的技巧:如果您要扩展工厂类,那么您正在使用抽象工厂。如果您使用创建方法扩展类,那么您正在使用工厂方法。

Your Creator class is the factory. Let's call it ProductFactory, in order to make the example more explicit.

(i am assuming you are using 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();
        [...]
    }
  }
}

Call it like this:

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

So, to answer your question:

What does it have to do with subclasses? And what am I supposed to use
subclasses for?

What the definition for factory pattern is saying is that the factory defines a common API for creating instances of a certain type (normally an interface or abstract class), but the real type of the implementations returned (thus the subclass reference) is the responsibility of the factory. In the example, the factory returns Product instances, for which Book and Computer are valid subclasses.

There are other idioms for factory, like having an API for the factory and the concrete implementations of the factory do not accept a type like in my example, but they are coupled with the type of instances returned, like this:

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

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

In this class BookProductFactory always returns Book instances.

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

To make it clear, since there seems to be a bit of confusion between Abstract Factory and Factory method design patterns, let's see a concrete example:

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

That is used like this:

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;

Using Factory method

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

That is used like this:

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

When you use a type discriminator like I did in the original example, we are using parametized factory methods - a method that knows how to create different kind of objects. But that can appear in either an Abstract Factory or Factory Method pattern. A brief trick: if you are extending the factory class you are using Abstract Factory. If you extending the class with the creation methods, then you are using Factory Methods.

拥抱影子 2024-12-12 04:34:38

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

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

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

Factory pattern merely means that there is some Factory class or method whose responsibility is to create objects for you; instead of you instantiating them yourself. Much like cars are built in factories so you don't have to.

It has nothing to do with sub classes however the author might be trying to say that factory can often return you derived implementation of a base class based on your parameters because that subclass may do what you're asking for in parameters.

For example WebRequest.Create("http://www.example.com") would return me HttpWebRequest but WebRequest.Create("ftp://www.example.com") would return me FtpWebRequest because both have different protocols which are implemented by different classes but the public interface is same so this decision doesn't have to be taken by consumer of my API.

初与友歌 2024-12-12 04:34:38

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

Product Make() will make the correct type (subclass) of product based on certain conditions and "defer" the actual instantiation to the specific products.

(psuedo code)

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

Factory hides the required conditional details for constructing the various product types. Secondly, IMHO, from the API user point of view, it is usually easier to see what product types there are (usually from an enum) and easier to create them from a single point of creation.

伴随着你 2024-12-12 04:34:38

简单简短:

工厂中,会检查请求实例化哪个“子类”,因此“让子类决定实例化哪个类”
您在必须做出决定的工厂类中使用条件语句。

“定义用于创建对象的接口或抽象类”。显然,您将对象存储到接口的引用中,并且客户端不知道返回的是哪个具体类的对象。 (因此您定义了一个接口来创建对象)。

Simple and short:

In the factory, it is checked which "subclass" is requested to instantiate so "let the subclasses decide which class to instantiate"
(You use conditional statements in factory class where decision has to be made.)

"define an interface or abstract class for creating an object". obviously, you store the object into interface's reference and the client is unaware which concrete class's object is returned. (So you defined an interface to create an object).

徒留西风 2024-12-12 04:34:38

我只能假设他的意思是这样的:

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

但这不是创建工厂的标准方法。

I can only assume he means this:

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

However this is not a standard way to create a factory.

三生路 2024-12-12 04:34:38

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

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

Providing such examples in pseudo-code is a bit confusing, the pattern is very language-dependent. Your example looks like in C++, but it's invalid in C++ because make returns Product by value. This is completely against the main goal of Factory - to return a reference (pointer in C++ case) to base class. Some answers take this as C# or Java (I guess) when others as C++.

Factory pattern relies on polymorphism. The key point is to return a reference to base Product class. Children of Factory will create instances of concrete classes.

柳若烟 2024-12-12 04:34:38

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

I have the same confusion "let the subclasses decide which class to instantiate " -Because in implementation factory method using new to create an object" - I refer Head first design pattern book in which its clearly stated about this as follows -
"As in the official definition you will hear often developers says that let the subclass decide which class to instantiate .They say "decides"not because the pattern allows subclass themselves to decide runtime ,but because the creator class is written w/o knowledge of the actual product that will be created ,which is decided purely by the choice of the subclass that is used "

萌化 2024-12-12 04:34:38

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

Factory Method is a creational design pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created. This example illustrates how the Factory Method can be used for creating cross-platform UI elements without coupling the client code to concrete UI classes.

// 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()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文