Wzór fabryczny. Kiedy stosować metody fabryczne?

Odpowiedzi:

387

Lubię myśleć o wzorach projektowych w kategoriach tego, że moje zajęcia są „ludźmi”, a wzorce są sposobem, w jaki ludzie rozmawiają ze sobą.

Tak więc według mnie wzór fabryczny jest jak biuro pośrednictwa pracy. Masz kogoś, kto będzie potrzebował zmiennej liczby pracowników. Ta osoba może znać pewne informacje na temat zatrudnionych osób, ale to wszystko.

Kiedy potrzebują nowego pracownika, dzwonią do agencji pośrednictwa pracy i mówią im, czego potrzebują. Teraz, aby faktycznie kogoś zatrudnić , musisz wiedzieć wiele rzeczy - korzyści, weryfikację uprawnień itp. Ale osoba zatrudniająca nie musi nic o tym wiedzieć - agencja rekrutacyjna zajmuje się tym wszystkim.

W ten sam sposób korzystanie z fabryki pozwala konsumentowi tworzyć nowe obiekty bez konieczności poznawania szczegółów ich tworzenia ani zależności od nich - muszą jedynie podać informacje, których naprawdę potrzebują.

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

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

Tak więc teraz konsument ThingFactory może uzyskać Rzecz bez konieczności znajomości zależności Rzeczy, z wyjątkiem danych łańcuchowych, które pochodzą od konsumenta.

Kyoryu
źródło
17
Gdzie konkretna implementacja GetThing () pobiera wartości firstDependency i secondDependency?
Mikeyg36
88
Czy ktoś mógłby mi powiedzieć, jak to odpowiada na pytanie OP? To tylko opisuje, czym jest „Wzór fabryczny”, a następnie dodaje przykład „Metoda fabryczna”, która jest tylko jednym z trzech „Wzorów fabrycznych”. Innymi słowy, nigdzie nie widzę porównania.
Myśliciel
4
Pytanie OP wyraźnie wymienia within an object instead of a Factory class. Myślę, że miał na myśli scenariusz, w którym uczynisz ctor prywatnym i użyjesz metody statycznej, aby utworzyć instancję klasy (stworzyć obiekt). Aby jednak podążać za tym przykładem, należy najpierw utworzyć instancję ThingFactoryklasy, aby uzyskać Thingobiekty, co powoduje, że działa to Factory classpoprawnie.
atiyar
4
Przykro nam, ale wyjaśnienie jest badziewne, ponieważ konstruktor można również napisać w taki sposób, aby ukryć zależności. Brakuje kluczowych informacji w tle, które chcesz oddzielić informacje o tworzeniu zależności od zarządzania zależnościami. Poza tym pytanie dotyczyło tej samej klasy, odpowiedź nie jest z tym związana.
Christian Hujer,
8
OP zapytał, kiedy . Kyoryu odpowiedział jak . Chociaż styl odpowiedzi jest godny pochwały, w kontekście tego pytania jest to tylko hałas.
8bitjunkie
96

Metody fabryczne należy traktować jako alternatywę dla konstruktorów - głównie wtedy, gdy konstruktory nie są wystarczająco ekspresyjne, tj.

class Foo{
  public Foo(bool withBar);
}

nie jest tak wyrazisty jak:

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

Klasy fabryczne są przydatne, gdy potrzebujesz skomplikowanego procesu konstruowania obiektu, gdy konstrukcja wymaga zależności, której nie chcesz dla rzeczywistej klasy, gdy potrzebujesz konstruować różne obiekty itp.

Rasmus Faber
źródło
2
Gdzie jest tutaj klasa Factory?
Koray Tugay
20
@KorayTugay: Nie ma klasy fabrycznej, tylko metody fabryczne. Pytanie dotyczy tego, kiedy zastosować metody fabryczne zamiast klasy fabrycznej. Ale metody fabryczne są bardziej alternatywą dla konstruktorów niż alternatywą dla klas fabrycznych. (Nie wiem, dlaczego najwyższa odpowiedź jest tak wysoko oceniana, mimo że mówi się tylko o klasach fabrycznych).
Rasmus Faber
5
Należy zauważyć, że statyczne metody fabryczne są całkowicie różne od wzorca projektowego Gang of Four: Factory Method.
jaco0646,
76

Jedną z sytuacji, w której osobiście uważam, że osobne klasy Factory mają sens, jest to, że ostateczny obiekt, który próbujesz stworzyć, opiera się na kilku innych obiektach. Np. W PHP: Załóżmy, że masz Houseobiekt, który z kolei ma a Kitcheni LivingRoomobiekt, a LivingRoomobiekt maTV obiekt wewnątrz, jak również.

Najprostszym sposobem na osiągnięcie tego jest utworzenie przez każdy obiekt swoich dzieci na podstawie metody konstruowania, ale jeśli właściwości są względnie zagnieżdżone, gdy Housetworzenie się nie powiedzie, prawdopodobnie poświęcisz trochę czasu na wyodrębnienie tego, co nie działa.

Alternatywą jest wykonanie następujących czynności (wstrzyknięcie zależności, jeśli podoba Ci się wymyślny termin):

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

Tutaj, jeśli proces tworzenia Houseawarii kończy się niepowodzeniem, jest tylko jedno miejsce do patrzenia, ale konieczność korzystania z tego fragmentu za każdym razem, gdy chce się nowego, Housejest daleka od wygody. Wejdź do fabryk:

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

Dzięki fabryce proces tworzenia a Housejest abstrakcyjny (w tym sensie, że nie musisz tworzyć i konfigurować każdej zależności, gdy chcesz tylko utworzyć a House), a jednocześnie scentralizowany, co ułatwia utrzymanie. Są inne powody, dla których korzystanie z oddzielnych fabryk może być korzystne (np. Testowalność), ale ten konkretny przypadek użycia znajduję, aby najlepiej zilustrować, w jaki sposób klasy fabryczne mogą być przydatne.

Mahn
źródło
1
Jak jednak ktoś przeprowadziłby test jednostkowy? Myślałem, że użycie słowa kluczowego „nowy” w klasie zostało uznane za złą praktykę, ponieważ nie można go przetestować jednostkowo. A może fabryka ma stanowić wyjątek od tej reguły?
AgmLauncher,
1
@AgmLauncher Miałem to samo pytanie, kiedy zacząłem z testowaniem jednostkowym, sprawdź: stackoverflow.com/questions/10128780/…
Mahn
1
Nie dostałem tego. W jaki sposób parametry tworzenia różnych obiektów są przekazywane HouseFactoryklasie?
atiyar
1
@Mahn, czy nie skończyłbyś w końcu z wieloma parametrami?
Pacerier
1
@Pacerier to coś, co możesz zdecydować, jak modelować, w zależności od potrzeb, ale nie zawsze musisz przekazać każdy parametr do createmetody. Np. Jeśli twój Housezawsze będzie miał taki sam rodzaj, LivingRoomsensowne może być zapisanie jego parametrów w klasie fabrycznej zamiast podania ich jako argumentu. Lub możesz podać typeargument do swojej HouseFactory::createmetody, jeśli masz kilka rodzajów LivingRoomsi i masz przełącznik z parametrami zakodowanymi na stałe dla każdego typu.
Mahn
19

Ważne jest, aby wyraźnie rozróżnić pomysł za pomocą metody fabrycznej lub fabrycznej. Oba mają na celu rozwiązywanie wzajemnie wykluczających się różnych problemów związanych z tworzeniem obiektów.

Powiedzmy konkretnie o „metodzie fabrycznej”:

Po pierwsze, kiedy tworzysz bibliotekę lub interfejsy API, które z kolei będą wykorzystywane do dalszego rozwoju aplikacji, wówczas metoda fabryczna jest jednym z najlepszych wyborów wzorca tworzenia. Powód za; Wiemy, że kiedy utworzyć obiekt o wymaganych funkcjach, ale typ obiektu pozostanie niezdecydowany lub zostanie podjęta decyzja o przekazaniu parametrów dynamicznych .

Chodzi o to, że w przybliżeniu to samo można osiągnąć przy użyciu samego wzorca fabrycznego, ale jedna wielka wada wprowadzi się do systemu, jeśli wzorzec fabryczny zostanie użyty do wyżej wymienionego problemu, jest to, że twoja logika tworzenia różnych obiektów (obiektów podklas) będzie bądź specyficzny dla niektórych warunków biznesowych, więc w przyszłości, gdy będziesz musiał rozszerzyć funkcjonalność swojej biblioteki na inne platformy (technicznie rzecz biorąc, musisz dodać więcej podklas podstawowego interfejsu lub klasy abstrakcyjnej, aby fabryka zwróciła te obiekty oprócz istniejącej na podstawie niektórych parametrów dynamicznych), a następnie za każdym razem, gdy trzeba zmienić (rozszerzyć) logikę klasy fabrycznej, co będzie kosztowne, a nie dobre z punktu widzenia projektu. Z drugiej strony, jeśli „metoda fabryczna”

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();
    }
}
Prakash Chhipa
źródło
15

Przydają się również, gdy potrzebujesz kilku „konstruktorów” o tym samym typie parametru, ale o innym zachowaniu.

Rik
źródło
15

Dobrym pomysłem jest stosowanie metod fabrycznych wewnątrz obiektu, gdy:

  1. Klasa obiektu nie wie, jakie dokładnie podklasy musi utworzyć
  2. Klasa obiektu została zaprojektowana tak, aby obiekty, które tworzy, były określone przez podklasy
  3. Klasa Object deleguje swoje obowiązki do pomocniczych podklas i nie wie, jaką dokładnie klasa podejmie te obowiązki

Dobrym pomysłem jest użycie abstrakcyjnej klasy fabrycznej, gdy:

  1. Twój obiekt nie powinien zależeć od tego, jak są tworzone i projektowane jego wewnętrzne obiekty
  2. Grupa połączonych obiektów powinna być używana razem i musisz spełnić to ograniczenie
  3. Obiekt powinien zostać skonfigurowany przez jedną z kilku możliwych rodzin połączonych obiektów, które będą częścią obiektu nadrzędnego
  4. Wymagane jest udostępnianie obiektów potomnych zawierających tylko interfejsy, ale nie implementację
Dzianis Yafimau
źródło
9

UML od

wprowadź opis zdjęcia tutaj

Produkt: Definiuje interfejs obiektów tworzonych przez metodę Factory.

Produkt betonowy: Implementuje interfejs produktu

Twórca: Deklaruje metodę Factory

ConcreateCreator: implementuje metodę Factory w celu zwrócenia instancji ConcreteProduct

Stwierdzenie problemu: Utwórz fabrykę gier za pomocą metod fabrycznych, które definiują interfejs gry.

Fragment kodu:

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

wynik:

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

Ten przykład pokazuje Factoryklasę, implementując FactoryMethod.

  1. Gamejest interfejsem dla wszystkich rodzajów gier. Definiuje złożoną metodę:createGame()

  2. Chess, Ludo, Checkers są różne warianty gier, które zapewniają implementację do createGame()

  3. public Game getGame(String gameName)jest FactoryMethodw IGameFactoryklasie

  4. GameFactorywstępnie tworzy różne typy gier w konstruktorze. Implementuje IGameFactorymetodę fabryczną.

  5. Nazwa gry jest przekazywana jako argument wiersza poleceń do NotStaticFactoryDemo

  6. getGamein GameFactoryakceptuje nazwę gry i zwraca odpowiedni Gameobiekt.

Fabryka:

Tworzy obiekty bez ujawniania klientowi logiki tworzenia instancji.

FactoryMethod

Zdefiniuj interfejs do tworzenia obiektu, ale pozwól, aby podklasy zdecydowały, którą klasę utworzyć. Metoda Factory pozwala klasie odroczyć tworzenie instancji do podklas

Przypadek użycia:

Kiedy używać: Clientnie wie, jakie konkretne klasy będzie trzeba utworzyć w czasie wykonywania, ale chce tylko uzyskać klasę, która wykona zadanie.

Ravindra babu
źródło
dziękuję za sekcję uwag, jest dla mnie zwięzły. ale nie można sobie wyobrazić, że „getArea () jest fabryczną metodą w interfejsie Shape”, ponieważ metoda getArea NIGDY nie tworzy instancji żadnej klasy, po prostu wykonuje obliczenia. przegląd: „Zdefiniuj interfejs do tworzenia obiektu, ale pozwól, aby podklasy zdecydowały, którą klasę utworzyć „proszę”.
reco
getArea()Nie jest to metoda fabryki w ogóle .
Cranio
1
Mam inne zdanie - eksperci powinni potwierdzić i umieścić notatki. 1. Klient (lub wywołujący) potrzebuje Object of Interest ... dlatego nie powinien wywoływać nowego GameFactory (), a klasa Factory powinna mieć statyczny getInstance () 2. Również jeśli tak, to game.put (Chess.class.getName ( ), nowe szachy ()); zawsze zwróci to samo odniesienie do gry w szachy [jeśli zostanie zaimplementowane jako statyczne] - jak poradzić sobie z tym scenariuszem w najbardziej efektywny sposób?
Arnab Dutta
Podałem przykład fabryki niestatycznej. Jeśli chcesz, możesz zaimplementować go za pomocą bloków statycznych i metod. Odnośnie twoich zapytań: 1. Klient zadzwoni do fabryki, aby uzyskać grę. 2.
Kładę
6

To naprawdę kwestia gustu. Klasy fabryczne można w razie potrzeby wyodrębnić / powiązać, podczas gdy metody fabryczne są lżejsze (a także zwykle są testowalne, ponieważ nie mają określonego typu, ale będą wymagały znanego punktu rejestracji, podobnego do usługi lokalizator, ale do lokalizowania metod fabrycznych).

Brad Wilson
źródło
4

Klasy fabryczne są przydatne, gdy zwracany typ obiektu ma prywatny konstruktor, gdy różne klasy fabryczne ustawiają różne właściwości zwracanego obiektu lub gdy określony typ fabryki jest sprzężony z jego zwracanym typem konkretnym.

WCF używa klas ServiceHostFactory do pobierania obiektów ServiceHost w różnych sytuacjach. Standardowy ServiceHostFactory jest używany przez IIS do pobierania instancji ServiceHost dla .svc plików , ale WebScriptServiceHostFactory jest używany dla usług, które zwracają serializacje do klientów JavaScript. Usługi danych ADO.NET mają swoje własne DataServiceHostFactory, a ASP.NET ma ApplicationServicesHostFactory, ponieważ ich usługi mają prywatnych konstruktorów.

Jeśli masz tylko jedną klasę, która pochłania fabrykę, możesz po prostu użyć metody fabrycznej w tej klasie.

Mark Cidade
źródło
2

Rozważ scenariusz, w którym musisz zaprojektować klasę zamówienia i klienta. Dla uproszczenia i wstępnych wymagań nie czujesz potrzeby fabryki dla klasy Order i wypełnij swoją aplikację wieloma oświadczeniami „new Order ()”. Wszystko działa dobrze.

Teraz pojawia się nowe wymaganie, że obiekt zamówienia nie może zostać utworzony bez skojarzenia klienta (nowa zależność). Teraz masz następujące uwagi.

1- Tworzysz przeciążenie konstruktora, które będzie działać tylko w przypadku nowych implementacji. (Nie do zaakceptowania). 2- Zmieniasz podpisy Order () i zmieniasz każde wywołanie. (Nie jest to dobra praktyka i prawdziwy ból).

Zamiast tego Jeśli utworzyłeś fabrykę dla klasy zamówień, musisz zmienić tylko jeden wiersz kodu i możesz zacząć. Sugeruję klasę fabryczną dla prawie każdego skojarzenia. Mam nadzieję, że to pomaga.

Muhammad Awais
źródło
1

jeśli chcesz stworzyć inny obiekt pod względem użytkowania. To jest użyteczne.

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;
      }
}
Samet ÖZTOPRAK
źródło
1

Każda klasa odraczająca tworzenie obiektu do swojej podklasy dla obiektu, z którym musi pracować, może być postrzegana jako przykład wzorca fabrycznego.

Wspominałem szczegółowo w innej odpowiedzi na https://stackoverflow.com/a/49110001/504133

nits.kk
źródło
1

Myślę, że będzie to zależeć od luźnego stopnia sprzężenia, który chcesz wprowadzić do swojego kodu.

Metoda fabryczna oddziela rzeczy bardzo dobrze, ale klasa fabryczna nr.

Innymi słowy, łatwiej jest zmieniać rzeczy, jeśli używasz metody fabrycznej niż w przypadku prostej fabryki (znanej jako klasa fabryczna).

Spójrz na ten przykład: https://connected2know.com/programming/java-factory-pattern/ . Teraz wyobraź sobie, że chcesz przynieść nowe zwierzę. W klasie Factory musisz zmienić fabrykę, ale w metodzie fabrycznej nie, musisz tylko dodać nową podklasę.

tagus
źródło
0

Klasy fabryczne są bardziej ciężkie, ale dają pewne korzyści. W przypadkach, gdy musisz zbudować swoje obiekty z wielu surowych źródeł danych, pozwalają one na enkapsulację tylko logiki budynku (i być może agregacji danych) w jednym miejscu. Tam można go przetestować abstrakcyjnie, nie zajmując się interfejsem obiektowym.

Uznałem to za użyteczny wzorzec, szczególnie tam, gdzie nie jestem w stanie zastąpić i nieadekwatnej ORM i chcę wydajnie tworzyć instancje wielu obiektów z połączeń DB lub procedur przechowywanych.

jonfm
źródło
0

Porównuję fabryki do koncepcji bibliotek. Na przykład możesz mieć bibliotekę do pracy z liczbami i inną do pracy z kształtami. Możesz przechowywać funkcje tych bibliotek w logicznie nazwanych katalogach jako NumberslubShapes . Są to typy ogólne, które mogą obejmować liczby całkowite, liczby zmiennoprzecinkowe, dobule, długie lub prostokąty, koła, trójkąty, pięciokąty w przypadku kształtów.

Petter w fabryce wykorzystuje polimorfizm, wstrzykiwanie zależności i odwracanie kontroli.

Deklarowanym celem Wzorów Fabrycznych jest: Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Powiedzmy, że budujesz system operacyjny lub platformę i budujesz wszystkie dyskretne komponenty.

Oto prosty przykład koncepcji wzorca fabrycznego w PHP. Może nie jestem w 100% na tym wszystkim, ale ma to służyć jako prosty przykład. Nie jestem ekspertem.

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 );
Robert Rocha
źródło
Rozumiem, co się tutaj dzieje, ale nie rozumiem, o co w tym chodzi. Co NumbersFactory::makeNumber( 'float', 12.5 );sprawia, że ​​mówię, new Float(12.5);jeśli wiem, że potrzebuję Float? Tego nie rozumiem w fabrykach ... o co chodzi?
BadHorsie,
Pozwala wybrać różne implementacje i nie wiąże Cię tylko z jedną. Interfejs został ustanowiony i wszystkie implementacje muszą go zagwarantować i honorować.
Robert Rocha,