简体   繁体   中英

Factory Pattern: Supporting new concrete types

I was studying about Factory Pattern in this link. After writing a normal factory, the author goes on to design a factory where we don't have to modify the factory's code to add new concrete implementations. (Let's say there's a Product interface and factory provides it's implementations).

To achieve this, the author says:

We add a new abstract method in the product abstract class. Each concrete class will implement this method to create a new object of the same type as itself.

And this code snippet follows:

 abstract class Product
{
    public abstract Product createProduct();
    ...
}

class OneProduct extends Product
{
    ...
    static
    {
        ProductFactory.instance().registerProduct("ID1", new OneProduct());
    }
    public OneProduct createProduct()
    {
        return new OneProduct();
    }
    ...
}

class ProductFactory
{
    public void registerProduct(String productID, Product p)    {
        m_RegisteredProducts.put(productID, p);
    }

    public Product createProduct(String productID){
        ((Product)m_RegisteredProducts.get(productID)).createProduct();
    }
}

I have a doubt here. We are already registering an instance of OneProduct to the factory. Then at runtime, we are calling createProduct() method which again creates a new instance of Oneproduct .

Is this the correct way of doing this? We have to create two instances of OneProduct here which I feel is wrong.

The reason why you need two instances is that you are using polymorphism when you call the createProduct() method. That is, each concrete product has its own implementation of createProduct() , and you can use the method to create all of them in the same way, because they all inherit from the same abstract class.

But to do that, you need to have instances. You cannot use polymorphism with static methods. You can only override instance methods. Thus you need an instance, to create an instance.

However, it's not necessary that the instance will be of the same type that it creates. It just needs to be an instance of a class that implements the required method. In Java 8, you could probably get a cleaner solution using Supplier<Product> .

abstract class Product
{
    ...
}

class OneProduct extends Product
{
    ...
    static
    {
        ProductFactory.instance().registerProduct("ID1", OneProduct::new);
    }
    ...
}

class ProductFactory
{
    Map<String,Supplier<Product>> m_RegisteredProducts = new HashMap<>();

    public void registerProduct(String productID, Supplier<Product> p)    {
        m_RegisteredProducts.put(productID, p);
    }

    public Product createProduct(String productID){
        // There should be a null check here...
        return m_RegisteredProducts.get(productID).get();
    }
}

In essence, the method reference gives you a small object that implements Supplier<Product> , on which you can call get() , which will create a new product using the default constructor.

The article you referred to is very old. I believe it predates Java 1.2, because it still uses a Hashtable rather than a modern map, and no generics. The principles remain the same but there are more modern ways of implementing them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM