Заводская модель: поддержка новых типов бетона - PullRequest
1 голос
/ 11 марта 2019

Я изучал около Factory Pattern по этой ссылке. После написания обычной фабрики автор переходит к разработке фабрики, где нам не нужно изменять код фабрики, чтобы добавить новые конкретные реализации. (Допустим, есть Product интерфейс и фабрика обеспечивает его реализацию).

Для этого автор говорит:

Мы добавляем новый абстрактный метод в абстрактный класс продукта. Каждый конкретный класс будет реализовывать этот метод для создания нового объекта того же типа, что и он сам.

И этот фрагмент кода следует:

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

У меня есть сомнение здесь. Мы уже регистрируем экземпляр OneProduct на заводе. Затем во время выполнения мы вызываем метод createProduct(), который снова создает новый экземпляр Oneproduct.

Это правильный способ сделать это? Мы должны создать два экземпляра из OneProduct здесь, которые я считаю неправильными.

1 Ответ

1 голос
/ 11 марта 2019

Причина, по которой вам нужны два экземпляра, заключается в том, что вы используете полиморфизм при вызове метода createProduct().То есть каждый конкретный продукт имеет свою собственную реализацию createProduct(), и вы можете использовать метод для их создания одинаковым образом, поскольку все они наследуются от одного абстрактного класса.

Но для этогочто вам нужно иметь экземпляры.Вы не можете использовать полиморфизм со статическими методами.Вы можете переопределить только методы экземпляра.Таким образом, вам нужен экземпляр для создания экземпляра.

Однако не обязательно, чтобы экземпляр был того же типа, который он создает.Это просто должен быть экземпляр класса, который реализует требуемый метод.В Java 8 вы, вероятно, могли бы получить более чистое решение, используя 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();
    }
}

По сути, ссылка на метод дает вам небольшой объект, который реализует Supplier<Product>, для которого вы можете вызвать get(), который создаст новый продукт с использованием конструктора по умолчанию.

Статья, на которую вы ссылались, очень старая.Я полагаю, что это предшествовало Java 1.2, потому что это все еще использует Hashtable, а не современную карту, и никаких обобщений.Принципы остаются прежними, но существуют более современные способы их реализации.

...