Factory Образец. Когда использовать методы Factory?

Когда полезно использовать методы factory внутри объекта вместо класса factory?

Ответ 1

Мне нравится думать о дизайне pattens с точки зрения того, что мои классы являются "людьми", и шаблоны - это способы, которыми люди разговаривают друг с другом.

Итак, для меня шаблон factory похож на агентство по найму. У вас есть кто-то, кому потребуется переменное количество рабочих. Этот человек может знать некоторую информацию, которая им нужна в людях, которых они нанимают, но что она.

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

Таким же образом использование factory позволяет потребителю создавать новые объекты, не зная подробностей о том, как они созданы или каковы их зависимости, - они должны только предоставить информацию, которую они действительно хотят.

public interface IThingFactory
{
    Thing GetThing(string theString);
}

public class ThingFactory : IThingFactory
{
    public Thing GetThing(string theString)
    {
        return new Thing(theString, firstDependency, secondDependency);
    }
}

Итак, теперь потребитель ThingFactory может получить Thing без необходимости знать о зависимостях Thing, за исключением строковых данных, которые поступают от пользователя.

Ответ 2

Factory следует рассматривать как альтернативу конструкторам - в основном, когда конструкторы недостаточно выразительны, т.е.

class Foo{
  public Foo(bool withBar);
}

не так выразителен, как:

class Foo{
  public static Foo withBar();
  public static Foo withoutBar();
}

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

Ответ 3

Одна из ситуаций, когда я лично нахожу отдельные классы Factory, чтобы понять, когда конечный объект, который вы пытаетесь создать, полагается на несколько других объектов. Например, в PHP: предположим, что у вас есть объект House, который, в свою очередь, имеет объект Kitchen и LivingRoom, а объект LivingRoom также имеет объект TV.

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

Альтернативой является сделать следующее (инъекция зависимости, если вам нравится этот термин):

$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);

Здесь, если процесс создания House не удался, есть только одно место для поиска, но при необходимости использовать этот кусок каждый раз, когда требуется новый House, это далеко не удобно. Введите фабрики:

class HouseFactory {
    public function create() {
        $TVObj = new TV($param1, $param2, $param3);
        $LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
        $KitchenroomObj = new Kitchen($param1, $param2);
        $HouseObj = new House($LivingroomObj, $KitchenroomObj);

        return $HouseObj;
    }
}

$houseFactory = new HouseFactory();
$HouseObj = $houseFactory->create();

Благодаря Factory здесь процесс создания House абстрагируется (при этом вам не нужно создавать и настраивать каждую отдельную зависимость, когда вы просто хотите создать House), и на централизованное централизованное управление, что упрощает его обслуживание. Существуют и другие причины, по которым использование отдельных заводов может быть полезным (например, тестируемость), но я нахожу этот конкретный пример использования, чтобы лучше всего показать, как могут быть полезны классы Factory.

Ответ 4

Важно четко различать идею использования метода factory или factory. Оба предназначены для решения взаимоисключающих различных проблем создания объектов.

Давайте укажем конкретный метод "factory":

Прежде всего, когда вы разрабатываете библиотеку или API, которые, в свою очередь, будут использоваться для дальнейшей разработки приложений, метод factory является одним из лучших вариантов для шаблона создания. Причина; Мы знаем, что когда для создания объекта требуемых функциональных возможностей, но тип объекта останется неопределенным или будет принято решение об отправке динамических параметров.

Теперь точка, примерно такая же может быть достигнута с использованием самого шаблона factory, но в систему будет введен один огромный недостаток, если шаблон factory будет использоваться для вышеописанной проблемы, это то, что ваша логика разбиения различных объекты (объекты подклассов) будут специфичны для некоторых бизнес-условий, поэтому в будущем, когда вам нужно расширить функциональность вашей библиотеки для других платформ (более технически вам нужно добавить дополнительные подклассы базового интерфейса или абстрактного класса, чтобы factory верните эти объекты также в дополнение к существующим на основе некоторых динамических параметров), то каждый раз, когда вам нужно изменить (расширить) логику класса factory, которая будет дорогостоящей операцией и не хороша с точки зрения дизайна. С другой стороны, если шаблон "factory method" будет использоваться для выполнения одной и той же вещи, вам просто нужно создать дополнительную функциональность (подклассы) и получить ее динамически динамически путем инъекции, которая не требует изменений в вашем базовом коде.

interface Deliverable 
{
    /*********/
}

abstract class DefaultProducer 
{

    public void taskToBeDone() 
    {   
        Deliverable deliverable = factoryMethodPattern();
    }
    protected abstract Deliverable factoryMethodPattern();
}

class SpecificDeliverable implements Deliverable 
{
 /***SPECIFIC TASK CAN BE WRITTEN HERE***/
}

class SpecificProducer extends DefaultProducer 
{
    protected Deliverable factoryMethodPattern() 
    {
        return new SpecificDeliverable();
    }
}

public class MasterApplicationProgram 
{
    public static void main(String arg[]) 
    {
        DefaultProducer defaultProducer = new SpecificProducer();
        defaultProducer.taskToBeDone();
    }
}

Ответ 5

Они также полезны, когда вам нужны несколько "конструкторов" с одним и тем же типом параметров, но с другим поведением.

Ответ 6

Рекомендуется использовать factory методы внутри объекта, когда:

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

Рекомендуется использовать абстрактный factory класс, когда:

  • Ваш объект не должен зависеть от того, как его внутренние объекты создаются и разрабатываются
  • Группа связанных объектов должна использоваться вместе, и вам необходимо выполнить это ограничение
  • Объект должен быть настроен одним из нескольких возможных семейств связанных объектов, которые будут частью вашего родительского объекта
  • Требуется разделить дочерние объекты, отображающие только интерфейсы, но не реализацию

Ответ 7

UML от

enter image description here

Product: определяет интерфейс объектов, создаваемых методом Factory.

ConcreteProduct: реализует интерфейс продукта

Создатель: объявляет фабричный метод

ConcreateCreator: реализует метод Factory для возврата экземпляра ConcreteProduct.

Постановка задачи: Создайте Фабрику Игр, используя Фабричные Методы, которые определяют интерфейс игры.

Фрагмент кода:

import java.util.HashMap;


/* Product interface as per UML diagram */
interface Game{
    /* createGame is a complex method, which executes a sequence of game steps */
    public void createGame();
}

/* ConcreteProduct implementation as per UML diagram */
class Chess implements Game{
    public Chess(){

    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Chess game");
        System.out.println("Opponents:2");
        System.out.println("Define 64 blocks");
        System.out.println("Place 16 pieces for White opponent");
        System.out.println("Place 16 pieces for Black opponent");
        System.out.println("Start Chess game");
        System.out.println("---------------------------------------");
    }
}
class Checkers implements Game{
    public Checkers(){

    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Checkers game");
        System.out.println("Opponents:2 or 3 or 4 or 6");
        System.out.println("For each opponent, place 10 coins");
        System.out.println("Start Checkers game");
        System.out.println("---------------------------------------");
    }
}
class Ludo implements Game{
    public Ludo(){

    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Ludo game");
        System.out.println("Opponents:2 or 3 or 4");
        System.out.println("For each opponent, place 4 coins");
        System.out.println("Create two dices with numbers from 1-6");
        System.out.println("Start Ludo game");
        System.out.println("---------------------------------------");
    }
}

/* Creator interface as per UML diagram */
interface IGameFactory {
    public Game getGame(String gameName);
}

/* ConcreteCreator implementation as per UML diagram */
class GameFactory implements IGameFactory {

     HashMap<String,Game> games = new HashMap<String,Game>();
    /*  
        Since Game Creation is complex process, we don't want to create game using new operator every time.
        Instead we create Game only once and store it in Factory. When client request a specific game, 
        Game object is returned from Factory instead of creating new Game on the fly, which is time consuming
    */

    public GameFactory(){

        games.put(Chess.class.getName(),new Chess());
        games.put(Checkers.class.getName(),new Checkers());
        games.put(Ludo.class.getName(),new Ludo());        
    }
    public Game getGame(String gameName){
        return games.get(gameName);
    }
}

public class NonStaticFactoryDemo{
    public static void main(String args[]){
        if ( args.length < 1){
            System.out.println("Usage: java FactoryDemo gameName");
            return;
        }

        GameFactory factory = new GameFactory();
        Game game = factory.getGame(args[0]);
        if ( game != null ){                    
            game.createGame();
            System.out.println("Game="+game.getClass().getName());
        }else{
            System.out.println(args[0]+  " Game does not exists in factory");
        }           
    }
}

выход:

java NonStaticFactoryDemo Chess
---------------------------------------
Create Chess game
Opponents:2
Define 64 blocks
Place 16 pieces for White opponent
Place 16 pieces for Black opponent
Start Chess game
---------------------------------------
Game=Chess

В этом примере показан класс Factory путем реализации FactoryMethod.

  1. Game является интерфейсом для всех типов игр. Он определяет сложный метод: createGame()

  2. Chess, Ludo, Checkers - это разные варианты игр, которые обеспечивают реализацию createGame()

  3. public Game getGame(String gameName) - это FactoryMethod в классе IGameFactory

  4. GameFactory предварительно создает различные типы игр в конструкторе. Он реализует фабричный метод IGameFactory.

  5. Имя игры передается в качестве аргумента командной строки в NotStaticFactoryDemo

  6. getGame в GameFactory принимает имя игры и возвращает соответствующий объект Game.

Фабрика:

Создает объекты, не раскрывая логику реализации клиенту.

FactoryMethod

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

Случай использования:

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

Ответ 8

Это действительно вопрос вкуса. Factory классы могут быть абстрагированы/сопряжены по мере необходимости, в то время как методы Factory являются более легким весом (а также, как правило, проверяемыми, поскольку они не имеют определенного типа, но для них потребуется известная точка регистрации, сродни локатору сервисов, но для определения методов Factory).

Ответ 9

Классы

Factory полезны, когда тип объекта, который они возвращают, имеет частный конструктор, когда разные классы factory устанавливают разные свойства для возвращаемого объекта или когда определенный тип factory связан с его возвращаемым бетоном тип.

WCF использует классы ServiceHostFactory для извлечения объектов ServiceHost в разных ситуациях. Стандартный ServiceHostFactory используется IIS для извлечения экземпляров ServiceHost для файлов .svc, но WebScriptServiceHostFactory используется для служб, которые возвращают сериализации для клиентов JavaScript. У ADO.NET Data Services есть собственный специальный DataServiceHostFactory, и ASP.NET имеет ApplicationServicesHostFactory, поскольку его службы имеют частные конструкторы.

Если у вас есть только один класс, который использует factory, вы можете просто использовать метод factory в этом классе.

Ответ 10

Рассмотрим сценарий, когда вам нужно создать класс Order и Customer. Для простоты и первоначальных требований вы не нуждаетесь в factory для класса Order и заполняете свое приложение множеством новых заказов Order(). Все хорошо работает.

Теперь возникает новое требование, что объект Order не может быть создан без ассоциации Customer (новая зависимость). Теперь у вас есть следующие соображения.

1- Вы создаете перегрузку конструктора, которая будет работать только для новых реализаций. (Недопустимо). 2- Вы меняете подписи Order() и меняете каждую инвокацию. (Не хорошая практика и настоящая боль).

Вместо этого Если вы создали factory для класса Order, вам нужно только изменить одну строку кода, и вам будет хорошо идти. Я предлагаю класс factory для почти каждой совокупной ассоциации. Надеюсь, что это поможет.

Ответ 11

Согласно источнику веб-сайта, его намерения заключаются в следующем:

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

  • Определение "виртуального" конструктора.

  • Новый оператор считается вредным.

Пример того, как это можно использовать:

abstract class AbstractFactoryMethod {
    abstract function makePHPBook($param);
}

class OReillyFactoryMethod extends AbstractFactoryMethod
{
    function makePHPBook($param)
    {
        $book = NULL;  
        switch ($param) {
            case "us":
                $book = new OReillyPHPBook();
            break;
            // Other classes...
            case "other":
                $book = new SamsPHPBook();
            break;
            default:
                $book = new OReillyPHPBook();
            break;        
    }

    return $book;
}

И затем тестирование:

function testFactoryMethod($factoryMethodInstance)
{
    $phpUs = $factoryMethodInstance->makePHPBook("us");
    echo 'us php Author: '.$phpUs->getAuthor();
    echo 'us php Title: '.$phpUs->getTitle();
}

echo 'Testing OReillyFactoryMethod';
$factoryMethodInstance = new OReillyFactoryMethod();
testFactoryMethod($factoryMethodInstance);

Ответ 12

Любой класс, откладывающий создание объекта до его подкласса для объекта, с которым он должен работать, можно рассматривать как пример шаблона Factory.

Я подробно упомянул в другом ответе на fooobar.com/questions/15266661/...

Ответ 13

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

Я нашел эту полезную модель, особенно когда я не могу заменить и неадекватную ORM и хочу эффективно создавать множество объектов из объединений таблиц БД или хранимых процедур.

Ответ 14

Я цитирую книгу PHP Masters.

Шаблон factory идеально подходит для создания одного из многих вариантов в настройке на основе драйверов, таких как разные механизмы хранения для вашей конфигурации, сеанса или кеша. Самое большое значение в шаблоне factory заключается в том, что он может инкапсулировать то, что обычно было бы большим количеством объектов в единый простой вызов метода. Например, при настройке объекта logger вам необходимо настроить тип журнала (например, на основе файлов, MySQL или SQLite), местоположение журнала и, возможно, такие элементы, как учетные данные.

Шаблон factory используется для расширения нового оператора при создании объектов и позволяет объединить сложности, которые могут возникнуть при настройке объекта, или многие типы похожих объектов.

Ответ 15

Я уподобляю фабрики концепции библиотек. Например, вы можете иметь библиотеку для работы с числами и другую для работы с фигурами. Вы можете хранить функции этих библиотек в логически названных каталогах как Numbers или Shapes. Это типичные типы, которые могут включать целые числа, поплавки, dobules, longs или прямоугольники, круги, треугольники, пятиугольники в случае фигур.

Петтер factory использует полиморфизм, инъекцию зависимостей и инверсию управления.

Заявленная цель шаблонов factory: Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Итак, скажем, что вы строите операционную систему или платформу, и вы строите все дискретные компоненты.

Вот простой пример концепции шаблона factory в PHP. Я не могу быть 100% от всего этого, но он должен служить простым примером. Я не эксперт.

class NumbersFactory {
    public static function makeNumber( $type, $number ) {
        $numObject = null;
        $number = null;

        switch( $type ) {
            case 'float':
                $numObject = new Float( $number );
                break;
            case 'integer':
                $numObject = new Integer( $number );
                break;
            case 'short':
                $numObject = new Short( $number );
                break;
            case 'double':
                $numObject = new Double( $number );
                break;
            case 'long':
                $numObject = new Long( $number );
                break;
            default:
                $numObject = new Integer( $number );
                break;
        }

        return $numObject;
    }
}

/* Numbers interface */
abstract class Number {
    protected $number;

    public function __construct( $number ) {
        $this->number = $number;
    }

    abstract public function add();
    abstract public function subtract();
    abstract public function multiply();
    abstract public function divide();
}
/* Float Implementation */
class Float extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}
/* Integer Implementation */
class Integer extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}
/* Short Implementation */
class Short extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}
/* Double Implementation */
class Double extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}
/* Long Implementation */
class Long extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}

$number = NumbersFactory::makeNumber( 'float', 12.5 );

Ответ 16

Пример AbstractFactory.

    TypeImpl<String> type = new TypeImpl<>();
    type.addType("Condition");
    type.addType("Hazardous");

    AbstractTypeFactory<String, Tag> tags = new AbstractTypeFactory<String, Tag>(type) {

        @Override
        public Tag create(String string) {
            String tp = type.find(string);

            switch (tp) {
                case "Hazardous":
                    return new HazardousTag();
                case "Condition":
                    return new ConditionTag();
                default:
                    return null;
            }
        }
    };

    Tag tagHazardous = tags.create("Hazardous");
    Tag tagCondition = tags.create("Condition");

}

Ответ 17

если вы хотите создать другой объект с точки зрения использования. Это полезно.

public class factoryMethodPattern {
      static String planName = "COMMERCIALPLAN";
      static int units = 3;
      public static void main(String args[]) {
          GetPlanFactory planFactory = new GetPlanFactory();
          Plan p = planFactory.getPlan(planName);
          System.out.print("Bill amount for " + planName + " of  " + units
                        + " units is: ");
          p.getRate();
          p.calculateBill(units);
      }
}

abstract class Plan {
      protected double rate;

      abstract void getRate();

      public void calculateBill(int units) {
            System.out.println(units * rate);
      }
}

class DomesticPlan extends Plan {
      // @override
      public void getRate() {
            rate = 3.50;
      }
}

class CommercialPlan extends Plan {
      // @override
      public void getRate() {
            rate = 7.50;
      }
}

class InstitutionalPlan extends Plan {
      // @override
      public void getRate() {
            rate = 5.50;
      }
}

class GetPlanFactory {

      // use getPlan method to get object of type Plan
      public Plan getPlan(String planType) {
            if (planType == null) {
                  return null;
            }
            if (planType.equalsIgnoreCase("DOMESTICPLAN")) {
                  return new DomesticPlan();
            } else if (planType.equalsIgnoreCase("COMMERCIALPLAN")) {
                  return new CommercialPlan();
            } else if (planType.equalsIgnoreCase("INSTITUTIONALPLAN")) {
                  return new InstitutionalPlan();
            }
            return null;
      }
}

Ответ 18

действительно посетите этот метод фабрики связи

это помогло мне понять эту вещь надеюсь, что то же самое для вас