it-swarm-tr.com

Fabrika düzeni. Fabrika yöntemleri ne zaman kullanılır?

Fabrika yöntemlerini bir fabrika sınıfı yerine bir nesnede kullanmak ne zaman iyidir?

249
jjshell

Sınıflarımın 'insanlar' olmaları açısından tasarım pattenleri hakkında düşünmeyi seviyorum ve kalıplar insanların birbirleriyle konuşma şekilleri.

Bu yüzden, bana göre fabrika düzeni bir işe alma ajansı gibidir. Değişken sayıda işçiye ihtiyaç duyacak birine sahipsin. Bu kişi, işe aldıkları kişilerde ihtiyaç duydukları bazı bilgileri biliyor olabilir, ancak bu kadar.

Böylece, yeni bir çalışana ihtiyaç duyduklarında, işe alım ajansını ararlar ve neye ihtiyaçları olduğunu söylerler. Şimdi, aslında işe birine, pek çok şey bilmeniz gerekiyor - faydalar, uygunluk doğrulaması, vb.

Aynı şekilde, bir Fabrika kullanımı, tüketicinin nasıl yaratıldıklarını ya da bağımlılıklarının ne olduğunu - bilmeden sadece gerçekte istedikleri bilgiyi vermek zorunda kalmadan yeni nesneler yaratmalarını sağlar.

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

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

Böylece, şimdi ThingFactory'nin tüketicisi, tüketiciden gelen dize verileri hariç, Thing'in bağımlılıklarını bilmek zorunda kalmadan bir Thing'i alabilir.

355
kyoryu

Fabrika yöntemleri, kuruculara bir alternatif olarak düşünülmelidir - çoğunlukla kurucular yeterince açıklayıcı olmadıklarında, yani.

class Foo{
  public Foo(bool withBar);
}

kadar anlamlı değil:

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

Fabrika sınıfları, nesneyi oluşturmak için karmaşık bir sürece ihtiyaç duyduğunuzda, inşaat gerçek sınıf için istemediğiniz bir bağımlılığa ihtiyaç duyduğunda, farklı nesneler inşa etmeniz gerektiğinde vs. kullanışlıdır.

84
Rasmus Faber

Şahsen anlam çıkarmak için ayrı ayrı Fabrika sınıfları bulduğum bir durum, yaratmaya çalıştığınız son nesnenin başka birkaç nesneye dayanmasıdır. E.g, PHP'de: __House ve Kitchen nesnesine sahip bir LivingRoom nesnesine sahip olduğunuzu ve LivingRoom nesnesinin içinde de bir TV nesnesine sahip olduğunu varsayalım. 

Bunu başarmanın en basit yöntemi, her nesnenin çocuklarını kendi yapı yönteminde yaratmalarını sağlamaktır, ancak özellikler nispeten iç içe geçmişse, House'niz oluşturmada başarısız olduğunda, muhtemelen tam olarak başarısız olanı izole etmeye çalışarak biraz zaman geçirirsiniz.

Alternatif, aşağıdakileri yapmaktır (fantezi terimini seviyorsanız bağımlılık enjeksiyonu):

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

Burada House oluşturma işlemi başarısız olursa, bakılacak tek bir yer var, ancak her biri yeni bir House istediğinde kullanmak zorunda kalmamak çok uygun. Fabrikaları Girin:

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

Buradaki fabrika sayesinde bir House oluşturma işlemi soyutlanır (sadece bir House oluşturmak istediğinizde her bir bağımlılığı yaratmanız ve ayarlamanız gerekmez) ve aynı zamanda merkezi hale getirilir; . Ayrı Fabrikaları kullanmanın faydalı olmasının (örneğin, test edilebilirlik) neden olmasının başka nedenleri de var, ancak bu özel kullanım durumunu Fabrika sınıflarının nasıl yararlı olabileceğini en iyi şekilde göstermek için buluyorum.

66
Mahn

Fabrika veya fabrika yöntemini kullanmanın ardındaki fikri açıkça ayırt etmek önemlidir. ... Her ikisi de birbirinden farklı, farklı nesne yaratma problemlerini ele almak içindir.

"Fabrika yöntemi" hakkında spesifik olalım:

Birincisi, daha sonra uygulama geliştirme için kullanılacak kütüphane veya API'ler geliştirirken, fabrika yönteminin yaratma modeli için en iyi seçimlerden biri olmasıdır. Sebep arkasındaki; Ne zaman gerekli işlevlerin bir nesnesinin ne zaman yaratılacağını biliyoruz, ancak nesne tipinin kararsız kalacağını ya da dinamik parametrelerin iletilmesine karar verileceğini biliyoruz.

Şimdi nokta şu ki, fabrika modelinin kendisi kullanılarak yaklaşık olarak aynı şey elde edilebilir, ancak yukarıda belirtilen problem için fabrika modelinin kullanılması durumunda sisteme büyük bir dezavantaj getirilecektir, farklı nesnelerin (alt sınıf nesneleri) sınıflandırılması mantığınız Gelecekte, kütüphanenizin işlevselliğini diğer platformlar için genişletmeniz gerektiğinde, bazı iş koşullarına özgü olun (Daha teknik olarak, temel arayüz veya soyut sınıfın daha alt sınıflarını eklemeniz gerekir; böylece fabrika, mevcut nesneleri ek olarak bu nesneleri de geri gönderir) Bazı dinamik parametrelere dayanarak) o zaman ne zaman pahalı çalışacak ve tasarım açısından iyi olmayacak fabrika sınıfının mantığını değiştirmeniz (uzatmanız) gerekiyorsa .. .. Diğer tarafta, eğer "fabrika metodu" paterni kullanılacaksa Aynı şeyi yapmak için, sadece ek işlevler (alt sınıflar) oluşturmanız ve temel kodunuzda değişiklik gerektirmeyen enjeksiyonla dinamik olarak kaydedilmesini sağlamanız yeterlidir.

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

Aşağıdaki durumlarda fabrika yöntemleri içindeki nesnelerin kullanılması iyi bir fikirdir:

  1. Nesnenin sınıfı, hangi tam alt sınıfları oluşturması gerektiğini bilmiyor
  2. Nesnenin sınıfı, oluşturduğu nesnelerin alt sınıflar tarafından belirtileceği şekilde tasarlanmıştır
  3. Nesnenin sınıfı, görevlerini yardımcı alt sınıflara devretti ve bu görevleri ne gibi bir sınıf alacağını bilmiyor

Aşağıdaki durumlarda soyut fabrika sınıfının kullanılması iyi bir fikirdir:

  1. Nesneniz, iç nesnelerin nasıl yaratıldığına ve tasarlandığına bağlı olmamalıdır
  2. Bağlantılı nesneler grubu birlikte kullanılmalı ve bu kısıtlamaya uymanız gerekir
  3. Nesne, üst nesnenizin bir parçası olacak olası nesnelerin birkaçı ile yapılandırılmalıdır.
  4. Arayüzleri gösteren alt nesnelerin sadece bir uygulama değil paylaşılması gerekmektedir.
14
Dzianis Yafimau

Aynı parametre türünde ancak farklı davranışlarda bulunan birkaç "yapıcıya" ihtiyacınız olduğunda da kullanışlıdırlar. 

14
Rik

Tarafından gönderilen UML 

 enter image description here

Product: Factory yönteminin oluşturduğu nesnelerin bir arayüzünü tanımlar.

ConcreteProduct: Ürün arayüzünü uygular

Oluşturan: Fabrika yöntemini bildirir

ConcreateCreator: ConcreteProduct örneğini döndürmek için Fabrika yöntemini uygular

Problem cümlesi: Oyun arayüzünü tanımlayan Fabrika Yöntemleri'ni kullanarak bir Fabrika Fabrikası oluşturun.

Kod pasajı:

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

çıktı:

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

Bu örnek, Factory uygulayarak FactoryMethod sınıfını gösterir.

  1. Game, her tür oyunun arayüzüdür. Karmaşık yöntemi tanımlar: createGame()

  2. Chess, Ludo, Checkers, createGame() öğesine uygulama sağlayan farklı oyun türevleridir.

  3. public Game getGame(String gameName), FactoryMethod sınıfındaki IGameFactory 'dir.

  4. GameFactory, yapıcıda farklı türde oyunlar önceden oluşturur. IGameFactory factory yöntemini uygular. 

  5. oyunun adı NotStaticFactoryDemo komut satırı argümanı olarak geçildi.

  6. getGame içinde GameFactory bir oyun adını kabul eder ve karşılık gelen Game nesnesini döndürür.

Fabrika:

Hazırlama mantığını istemciye göstermeden nesneler oluşturur.

FactoryMethod

Bir nesne oluşturmak için bir arabirim tanımlayın, ancak alt sınıfların hangi sınıfın başlatılacağına karar vermesine izin verin. Fabrika yöntemi, bir sınıfın alt sınıflara örneklenmeyi ertelemesini sağlar

Kullanım örneği:

Ne zaman kullanılır: Client, çalışma zamanında ne tür bir sınıf oluşturulması gerektiğini bilmez, ancak işi yapacak bir sınıf edinmek ister.

9
Ravindra babu

Bu gerçekten zevk meselesi. Fabrika sınıfları gerektiğinde soyutlanabilir/ara yüzlere ayrılabilir, oysa fabrika yöntemleri daha hafiftir (ve aynı zamanda test edilebilir olma eğilimindedirler çünkü tanımlanmış bir tipe sahip değillerdir, ancak bir hizmete benzer şekilde iyi bilinen bir kayıt noktasına ihtiyaç duyacaklardır konum belirleyici ancak fabrika yöntemlerini bulmak için).

5
Brad Wilson

Fabrika sınıfları, iade ettikleri nesne türünün özel bir kurucuya sahip olduğu zaman, farklı fabrika sınıfları dönen nesneye farklı özellikler ayarladığında veya belirli bir fabrika tipinin dönen beton tipiyle birleştiği durumlarda kullanışlıdır. 

WCF, farklı durumlarda ServiceHost nesnelerini almak için ServiceHostFactory sınıflarını kullanır. Standart ServiceHostFactory, IIS tarafından .svc dosyalarının ServiceHost örneklerini almak için kullanılır, ancak serileştirmeleri JavaScript istemcilerine döndüren hizmetler için bir WebScriptServiceHostFactory kullanılır. ADO.NET Data Services kendine ait DataServiceHostFactory özelliğine sahip olup, ASP.NET, ServiceServicesHostFactory hizmetine sahiptir, çünkü hizmetleri özel kuruculara sahiptir.

Fabrikayı tüketen yalnızca bir sınıfa sahipseniz, o sınıfta yalnızca bir fabrika yöntemi kullanabilirsiniz.

4
Mark Cidade

Bir Sipariş ve Müşteri sınıfı tasarlamanız gerektiğinde bir senaryo düşünün. Basitlik ve ilk gereksinimler için Order sınıfı için fabrikaya ihtiyaç duymuyorsunuz ve başvurunuzu birçok yeni Order () ifadesiyle dolduruyorsunuz. İşler iyi çalışıyor.

Şimdi, Müşteri birliği olmadan sipariş nesnesinin somutlanamayacağı yeni bir gereklilik ortaya çıkıyor (yeni bağımlılık). Şimdi aşağıdaki hususlara sahipsiniz.

1- Sadece yeni uygulamalar için çalışacak olan aşırı yükleyici yaratıyorsunuz. (Kabul edilemez) ..__ 2- Sipariş () imzalarını değiştirir ve her bir başvuruyu değiştirirsiniz. (İyi bir uygulama ve gerçek acı değil).

Bunun yerine, Sipariş Sınıfı için bir fabrika oluşturduysanız, yalnızca bir kod satırını değiştirmeniz gerekir ve gitmeniz iyi olur. Neredeyse her derneğin dernekleri için Fabrika sınıfını öneriyorum. Umarım yardımcı olur.

3
Muhammad Awais

Kaynak yapım web sitesine göre niyetleri:

  • Bir nesne oluşturmak için bir arabirim tanımlayın, ancak alt sınıfların hangi sınıfın başlatılacağına karar vermesine izin verin. Fabrika Yöntemi, bir sınıfın alt sınıflara örneklenmeyi ertelemesini sağlar.

  • Bir "sanal" kurucu tanımlamak.

  • Yeni operatör zararlı kabul edildi.

Nasıl kullanılabileceğine bir örnek:

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

Ve sonra test:

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);
3
Alexander Beat

Çalışması gereken nesne için nesnenin oluşturulmasını alt sınıfına erteleyen herhangi bir sınıf, Fabrika şablonunun bir örneği olarak görülebilir.

https://stackoverflow.com/a/49110001/504133 adresindeki başka bir yanıtta ayrıntılı olarak bahsetmiştim.

1
nits.kk

Fabrikaları kütüphaneler kavramına benzetiyorum. Örneğin, sayılarla çalışmak için bir kitaplığa ve şekiller ile çalışmak için başka bir kitaplığa sahip olabilirsiniz. Bu kitaplıkların işlevlerini mantıksal olarak adlandırılmış dizinlerde Numbers veya Shapes olarak saklayabilirsiniz. Bunlar, tamsayıları, kayan noktaları, dobulları, uzunları veya dikdörtgenleri, daireleri, üçgenleri, şekiller halinde beşgenleri içerebilen genel tiplerdir.

Fabrika petersinde polimorfizm, bağımlılık enjeksiyonu ve kontrolün tersine çevrilmesi kullanılır.

Fabrika Kalıplarının belirtilen amacı: Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Yani bir İşletim Sistemi veya Çerçeve oluşturduğunuzu ve tüm ayrı bileşenleri oluşturduğunuzu varsayalım.

İşte PHP'deki Fabrika Deseninin basit bir örneği. Hepsinde% 100 olmayabilirim ama bunun basit bir örnek teşkil etmesi gerekiyor. Ben uzman değilim.

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 );
0
Robert Rocha

Fabrika sınıfları daha ağırdır, ancak size bazı avantajlar sağlar. Nesnelerinizi birden fazla ham veri kaynağından oluşturmanız gerektiğinde, yalnızca bina mantığını (ve belki de verilerin toplanmasını) tek bir yerde saklamanıza izin verir. Burada nesne arayüzü ile ilgilenmeden soyut olarak test edilebilir.

Bunu, özellikle ORM'yi değiştiremediğim ve yetersiz hale getiremediğim ve çok sayıda nesneyi DB tablo birleşimlerinden veya depolanan prosedürlerden verimli bir şekilde başlatmak istediğim durumlarda faydalı bir desen buldum.

0
jonfm

AbstractFactory örneği.

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

}
0
Vahe Gharibyan

kullanma açısından farklı bir nesne oluşturmak istiyorsanız. Bu kullanışlı.

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;
      }
}
0
Samet öztoprak