Является ли метод Factory более подходящим для фреймворков и абстрактного фона для библиотеки?

Оба абстрактных шаблона метода Factory и Factory представляют собой шаблоны создания, которые решают проблемы создания объектов в разных сценариях.

В соответствии с шаблоном GOF Factory

Определите интерфейс для создания объекта, но пусть подклассы решают, какой класс необходимо создать. Метод Factory позволяет классу отложить создание экземпляра подкласса.

Мое понимание: Мотивация Клиент заключается в том, чтобы получить метод, присутствующий в базовом классе Factory, который будет выполняться, который зависит от объекта, чей конкретный класс сейчас неизвестен (в этом случае либо при предоставлении программного обеспечения для клиента он будет определен, или сам клиент будет писать конкретную реализацию, скорее всего, в случае Framework). Неизвестный (или может измениться) Продукт предоставляется абстрактный тип: IProduct и установка контракта, который в будущем любая реализация для продукта должна реализовать этот интерфейс.

Интерфейс IProduct

package com.companyx;
public interface IProduct {
    public void serve();
}

Factory класс с "методом", который необходимо выполнить

package com.companyx;
public abstract class Factory {
    public abstract IProduct createProduct();
    private void performCriticalJob(){
        IProduct product = createProduct();
        product.serve();
    }
    public void executeJob(){
        //some code
        performCriticalJob();
        //some more code
    }
}

Некоторое конкретное изделие

package com.companyx;
class AppAProductFeatureX implements IProduct{
    @Override
    public void serve() {
        //some code
    }
}

Factory конкретного продукта

package com.companyx;
public class AppAFeatureXProductFactory extends Factory{
    @Override
    public IProduct createProduct() {
        return new AppAProductFeatureX();
    }
}

Клиентский код

package com.clientcompany;
import com.companyx.AppAFeatureXProductFactory;
import com.companyx.Factory;
public class Client {
    public static void main(String[] args) {
        Factory fact = new AppAFeatureXProductFactory();
        fact.executeJob();
    }
}

В соответствии с GOF Абстрактный Factory шаблон

Предоставить интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.

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

Тип продукта, запрашиваемый клиентом

package com.companyb;
public interface IProductA {
    public void performAJob();
}

Реализация продукта

package com.companyb;
//can be named better, but lets go with this name for this time
public class ProductAVersion1 implements IProductA{
    @Override
    public void performAJob() {
        // some code
    }
}

Factory интерфейс, (он может быть также абстрактным классом)

package com.companyb;
public interface IFactory {
    public IProductA createProduct();
}

Конкретная реализация Factory o создать ProductA

пакет com.companyb;

public class FactoryA implements IFactory{
    @Override
    public IProductA createProduct() {
        return new ProductAVersion1(); // concrete class of product is hidden
    }
}

Код клиента

package com.clientcompany.productprovider;
import com.companyb.IFactory;
import com.companyb.IProductA;
public class SomeClientClass {
    private IFactory factory;
    private IProductA product;

    public void doSomeJobWithProductA() {
        // some code
        product.performAJob();
        //someCode();
    }
    public void setFactory(IFactory factory) {
        this.factory = factory;
        this.product = factory.createProduct();
    }
}

package com.clientcompany.productprovider;
import com.companyb.FactoryA;
public class SomeOtherClientCode {
    public static void main(String[] args) {
        SomeClientClass someClientClass = new SomeClientClass();
        someClientClass.setFactory(new FactoryA());
        someClientClass.doSomeJobWithProductA();
    }
}

Q1. Является ли семейство связанного продукта необходимым в абстрактном Factory patter, не будет ли этот шаблон актуальным, если существует только один вид продукта (например, выше) с различными подтипами но не различные родственные типы?

Q2 Является ли мое понимание выше правильного?

Q3 Вышеприведено еще одно сомнение: более подходит ли метод Factory для фреймворков (где клиент может предоставить реализацию продуктов) и точно так же, как шаблон метода шаблона, Factory вызывает createProduct() конкретная реализация формы, предоставляемой пользователем. Бетонная реализация Factory? Также аналогично Abstract Factory больше подходит для развития библиотеки, где конкретные классы продуктов (вероятно, будут меняться) скрыты за более стабильными классами Factory?

Ответ 1

У меня настоящая трудность в том, чтобы влезть в твою обувь. Но меня это очень интересует, поэтому я попробую. Здесь присутствуют такие понятия, как library, framework, factory method, abstract factory и product family и т.д.

Во-первых, library vs framework не имеет ничего общего с factory, абстрактным factory или любым шаблоном. Обсуждение библиотеки и фреймворка не связано с реализацией, на которой играют шаблоны. Например, JUnit - это структура, которая поставляется с богатой библиотекой утверждений. Так должен ли junit отдать предпочтение одному шаблону над другим для его внутренней реализации? Сама Java является основой, которая поставляется с библиотекой JCL. Dot Net, которая похожа на java, даже называет себя фреймворком и содержит библиотеку BCL. Таким образом, больше нет обсуждений в библиотеке в контексте реализации.

Итак, вопрос сводится к тому, какой шаблон следует использовать? Речь идет не о различии, которая ясна, а о том, какой из них использовать в каком сценарии. В этом контексте Client Code - это весь код, который может call тот, который вы печатаете прямо сейчас. Неважно, какой-либо код написан вами или кем-то другим, в том же или другом банке, из той же или другой организации. С точки зрения одного фрагмента кода любой другой код (даже в другом методе того же класса) является кодом клиента, если этот код имеет потенциал call кода, который вы печатаете прямо сейчас.

При наборе любого кода (независимо от структуры или статуса библиотеки) иногда нам нужно получить экземпляры какого-либо объекта. Может быть, нам нужен BufferedReader. Если во время компиляции мы абсолютно уверены в конкретном классе объекта, KISS и идем с new ing.

Мы можем не знать конкретного класса экземпляра. Теперь вопрос о том, имеет ли код клиента эту информацию? Если код клиента знает о конкретном конкретном классе, но я не знаю, мы используем шаблон FactoryMethod. Код, который я набираю, будет запрашивать экземпляр объекта factory в (скажем) его списке аргументов. Клиентский код, зная фактический конкретный класс, будет поставлять объект factory, который будет выполнять создание. Пример этого случая показан в JDBC так же, как мы хотим обработать инструкцию sql. Во время компиляции мы не знаем, следует ли создавать экземпляр mysql.JDBC4PreparedStatement или microsoft.SQLServerStatement. Это зависит от строки подключения и зависит от конечного пользователя. Итак, мы получаем экземпляр Connection и запрашиваем его createStatement(). См., Мы делегируем конструкцию объекта типа sql.Statement подклассу sql.Connection. Здесь экземпляр conn - это объект factory. То, как мы получаем factory, несущественно, просто мы получили его из клиентского кода.

Если нам нужен экземпляр объекта Process, и во время компиляции мы не знаем, будет ли он Win32Process или UnixProcess, мы делегируем ответственность за его создание на ProcessBuilder, который равен builder pattern, связанный с шаблоном factory. То же самое касается jdbc ConnectionManager.

Если существует много разных классов, не связанных по наследству, но family, мы можем использовать AbstractFactory. Например, возьмите jdbc dot net counter DbProviderFactory. Моему коду нужны экземпляры Connection, Command, DataReader и т.д., Которые не связаны наследованием, а семейством MySql или SqlServer. Итак, мы получаем экземпляр подкласса DbProviderFactory. Может быть, это MySqlProviderFactory или SqlProviderFactory, который зависит от времени исполнения и кода клиента. Как только мы получим factory, мы можем сделать CreateCommand(), CreateConnection() и т.д.

Надеемся, что это поможет вам выбрать шаблон factory и абстрактный шаблон factory.

Ответ 2

В моем понимании:

A1. Семейство продуктов необязательно должно быть связано, как показано на диаграмме , требуется только Клиент, обладающий знаниями о типе продуктов. Отношение в основном естественное, так как вы, вероятно, не хотите, чтобы один и тот же Клиент создал два несвязанных объекта, например, было бы странно, если у вас есть "AbstractPizzaFactory", который создает Pizza and Cars, no?

A2. Технически вы можете предоставить метод factory по умолчанию в шаблоне factory, чтобы вы все равно могли создавать (по умолчанию) новые объекты, не подвергая их обычному подклассу.

A3. Я согласен с вами в этом вопросе, хотя создание библиотеки или структуры никогда не будет черно-белым.

Ответ 3

Аннотация Factory можно рассматривать как набор методов Factory.

Для лучшего понимания примеров из реальной жизни может помочь:
Factory Метод - пластилин/плесень
Аннотация Factory - карты Factory