factory method design pattern

和自甴很熟 提交于 2019-12-21 04:40:56

问题


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?


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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).




回答5:


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.




回答6:


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.




回答7:


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 "



来源:https://stackoverflow.com/questions/7468104/factory-method-design-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!