it-swarm-id.com

Pola Pabrik. Kapan harus menggunakan metode pabrik?

Kapan ide yang baik untuk menggunakan metode pabrik dalam objek, bukan kelas Pabrik?

249
jjshell

Saya suka berpikir tentang pola desain dalam hal kelas saya menjadi 'orang,' dan polanya adalah cara orang berbicara satu sama lain.

Jadi, bagi saya pola pabrik seperti agen perekrutan. Anda memiliki seseorang yang membutuhkan sejumlah pekerja variabel. Orang ini mungkin mengetahui beberapa informasi yang mereka butuhkan pada orang yang mereka sewa, tetapi hanya itu.

Jadi, ketika mereka membutuhkan karyawan baru, mereka memanggil agen perekrutan dan memberi tahu mereka apa yang mereka butuhkan. Sekarang, untuk benar-benar merekrut seseorang, Anda perlu mengetahui banyak hal - manfaat, verifikasi kelayakan, dll. Tetapi orang yang direkrut tidak perlu mengetahui semua ini - agen perekrutan menangani semua itu.

Dengan cara yang sama, menggunakan Pabrik memungkinkan konsumen untuk membuat objek baru tanpa harus mengetahui detail bagaimana mereka dibuat, atau apa dependensi mereka - mereka hanya perlu memberikan informasi yang mereka inginkan.

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

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

Jadi, sekarang konsumen ThingFactory bisa mendapatkan Thing, tanpa harus tahu tentang ketergantungan Thing, kecuali untuk data string yang berasal dari konsumen.

355
kyoryu

Metode pabrik harus dianggap sebagai alternatif untuk konstruktor - kebanyakan ketika konstruktor tidak cukup ekspresif, yaitu.

class Foo{
  public Foo(bool withBar);
}

tidak se ekspresif seperti:

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

Kelas pabrik berguna ketika Anda membutuhkan proses rumit untuk membangun objek, ketika konstruksi membutuhkan ketergantungan yang tidak Anda inginkan untuk kelas aktual, ketika Anda perlu membangun objek yang berbeda dll.

84
Rasmus Faber

Satu situasi di mana saya secara pribadi menemukan kelas Pabrik terpisah masuk akal adalah ketika objek terakhir yang Anda coba buat bergantung pada beberapa objek lainnya. E.g, dalam PHP: Misalkan Anda memiliki objek House, yang pada gilirannya memiliki objek Kitchen dan LivingRoom, dan objek LivingRoom memiliki objek TV di dalamnya. 

Metode paling sederhana untuk mencapai ini adalah meminta setiap objek membuat anak-anak mereka pada metode konstruk mereka, tetapi jika properti relatif bersarang, ketika House Anda gagal dibuat, Anda mungkin akan meluangkan waktu untuk mencoba mengisolasi apa yang gagal.

Alternatifnya adalah dengan melakukan hal berikut (injeksi ketergantungan, jika Anda suka istilah mewah):

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

Di sini jika proses membuat House gagal hanya ada satu tempat untuk mencari, tetapi harus menggunakan potongan ini setiap kali seseorang ingin House baru jauh dari nyaman. Masukkan Pabrik:

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

Berkat pabrik di sini, proses membuat House diabstraksikan (di mana Anda tidak perlu membuat dan mengatur setiap ketergantungan tunggal ketika Anda hanya ingin membuat House) dan pada saat yang sama terpusat yang membuatnya lebih mudah untuk mempertahankan . Ada alasan lain mengapa menggunakan Pabrik yang terpisah dapat bermanfaat (mis. Kemampuan uji coba) tetapi saya menemukan kasus penggunaan khusus ini untuk mengilustrasikan terbaik bagaimana kelas Pabrik dapat bermanfaat.

66
Mahn

Penting untuk membedakan secara jelas ide di balik penggunaan metode pabrik atau pabrik .. Keduanya dimaksudkan untuk mengatasi berbagai jenis masalah penciptaan objek yang saling terpisah.

Mari kita lebih spesifik tentang "metode pabrik":

Hal pertama adalah bahwa, ketika Anda sedang mengembangkan perpustakaan atau API yang pada gilirannya akan digunakan untuk pengembangan aplikasi lebih lanjut, maka metode pabrik adalah salah satu pilihan terbaik untuk pola pembuatan. Alasan di balik; Kita tahu bahwa kapan membuat objek dengan fungsionalitas yang diperlukan, tetapi tipe objek akan tetap belum diputuskan atau akan diputuskan berdasarkan parameter dinamis yang dilewati .

Sekarang intinya adalah, kira-kira sama dapat dicapai dengan menggunakan pola pabrik itu sendiri tetapi satu kelemahan besar akan memperkenalkan ke dalam sistem jika pola pabrik akan digunakan untuk masalah yang disorot di atas, itu adalah bahwa logika Anda crating objek yang berbeda (objek kelas sub) akan spesifik untuk beberapa kondisi bisnis sehingga di masa mendatang ketika Anda perlu memperluas fungsionalitas perpustakaan Anda untuk platform lain (Secara lebih teknis, Anda perlu menambahkan lebih banyak sub kelas antarmuka dasar atau kelas abstrak sehingga pabrik akan mengembalikan benda-benda itu juga di samping yang sudah ada berdasarkan beberapa parameter dinamis) maka setiap kali Anda perlu mengubah (memperluas) logika kelas pabrik yang akan menjadi operasi yang mahal dan tidak baik dari perspektif desain ..__ Di sisi lain, jika pola "metode pabrik" akan digunakan untuk melakukan hal yang sama maka Anda hanya perlu membuat fungsionalitas tambahan (sub-kelas) dan mendaftarkannya secara dinamis dengan injeksi yang tidak memerlukan perubahan dalam kode dasar Anda.

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

Sebaiknya gunakan metode pabrik objek dalam saat:

  1. Kelas objek tidak tahu subkelas apa yang harus dibuatnya
  2. Kelas objek dirancang sehingga objek yang dibuatnya ditentukan oleh sub-kelas
  3. Kelas Object mendelegasikan tugasnya ke sub-kelas tambahan dan tidak tahu kelas yang tepat akan mengambil tugas ini

Adalah ide yang baik untuk menggunakan pabrik abstrak kelas ketika:

  1. Objek Anda seharusnya tidak bergantung pada bagaimana objek dalamnya dibuat dan dirancang
  2. Kelompok objek yang ditautkan harus digunakan bersama dan Anda harus melayani batasan ini
  3. Objek harus dikonfigurasikan oleh salah satu dari beberapa keluarga kemungkinan objek tertaut yang akan menjadi bagian dari objek induk Anda
  4. Hal ini diperlukan untuk berbagi objek anak yang menunjukkan antarmuka saja tetapi bukan implementasi
14
Dzianis Yafimau

Mereka juga berguna ketika Anda membutuhkan beberapa "konstruktor" dengan tipe parameter yang sama tetapi dengan perilaku yang berbeda. 

14
Rik

UML dari 

 enter image description here

Produk: Ini mendefinisikan antarmuka objek yang dibuat oleh metode Factory.

ConcreteProduct: Menerapkan antarmuka produk

Pencipta: Menyatakan metode Pabrik

ConcreateCreator: Menerapkan metode Factory untuk mengembalikan instance dari ConcreteProduct

Pernyataan masalah: Buat Pabrik Game dengan menggunakan Metode Pabrik, yang mendefinisikan antarmuka game.

Cuplikan kode:

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

keluaran:

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

Contoh ini menunjukkan kelas Factory dengan menerapkan FactoryMethod.

  1. Game adalah antarmuka untuk semua jenis game. Ini mendefinisikan metode yang kompleks: createGame()

  2. Chess, Ludo, Checkers adalah varian game yang berbeda, yang menyediakan implementasi untuk createGame()

  3. public Game getGame(String gameName) adalah FactoryMethod di IGameFactory kelas

  4. GameFactory pra-buat berbagai jenis gim dalam konstruktor. Ini menerapkan metode pabrik IGameFactory

  5. nama game dilewatkan sebagai argumen baris perintah ke NotStaticFactoryDemo

  6. getGame di GameFactory menerima nama permainan dan mengembalikan objek Game yang sesuai.

Pabrik:

Membuat objek tanpa memaparkan logika instantiation ke klien.

FactoryMethod

Tentukan antarmuka untuk membuat objek, tetapi biarkan subclass memutuskan kelas mana yang akan dipakai. Metode Factory memungkinkan class defer instantiation ke subclass

Use case:

Kapan harus menggunakan: Client tidak tahu kelas konkret apa yang harus dibuat saat runtime, tetapi hanya ingin mendapatkan kelas yang akan melakukan pekerjaan.

9
Ravindra babu

Ini benar-benar masalah selera. Kelas-kelas pabrik dapat diabstraksi/dihubung-hubungkan seperlunya, sedangkan metode-metode pabrik lebih ringan (dan juga cenderung dapat diuji, karena mereka tidak memiliki tipe yang ditentukan, tetapi mereka akan memerlukan titik registrasi yang terkenal, seperti layanan locator tetapi untuk menemukan metode pabrik).

5
Brad Wilson

Kelas pabrik berguna untuk ketika jenis objek yang mereka kembalikan memiliki konstruktor pribadi, ketika kelas pabrik yang berbeda menetapkan properti yang berbeda pada objek yang kembali, atau ketika jenis pabrik tertentu digabungkan dengan jenis betonnya yang kembali. 

WCFmenggunakan kelas ServiceHostFactory untuk mengambil objek ServiceHost dalam situasi yang berbeda. ServiceHostFactory standar digunakan oleh IIS untuk mengambil instance ServiceHost untuk file .svc, tetapi WebScriptServiceHostFactory digunakan untuk layanan yang mengembalikan serialisasi ke klien JavaScript. Layanan Data ADO.NET memiliki DataServiceHostFactory khusus dan ASP.NET memiliki ApplicationServicesHostFactory karena layanannya memiliki konstruktor pribadi.

Jika Anda hanya memiliki satu kelas yang mengkonsumsi pabrik, maka Anda bisa menggunakan metode pabrik dalam kelas itu.

4
Mark Cidade

Pertimbangkan skenario ketika Anda harus merancang kelas Pesanan dan Pelanggan. Untuk kesederhanaan dan persyaratan awal Anda tidak merasa perlu pabrik untuk kelas Order dan mengisi aplikasi Anda dengan banyak pernyataan 'Order baru ()'. Semuanya bekerja dengan baik.

Sekarang persyaratan baru muncul bahwa objek Pesanan tidak dapat dipakai tanpa asosiasi Pelanggan (ketergantungan baru). Sekarang Anda memiliki pertimbangan sebagai berikut.

1- Anda membuat kelebihan konstruktor yang hanya akan berfungsi untuk implementasi baru. (Tidak dapat diterima) . 2- Anda mengubah tanda tangan Order () dan mengubah masing-masing dan setiap invokation. (Bukan latihan yang baik dan rasa sakit yang nyata).

Alih-alih Jika Anda telah membuat pabrik untuk Kelas Pesanan, Anda hanya perlu mengubah satu baris kode dan Anda dapat melakukannya. Saya menyarankan kelas Pabrik untuk hampir setiap asosiasi agregat. Semoga itu bisa membantu.

3
Muhammad Awais

Menurut situs web pembuatan sumber, niatnya adalah:

  • Tentukan antarmuka untuk membuat objek, tetapi biarkan subclass memutuskan kelas mana yang akan dipakai. Metode Pabrik memungkinkan instantiasi penundaan kelas ke subclass.

  • Mendefinisikan konstruktor "virtual".

  • Operator baru dianggap berbahaya.

Contoh cara penggunaannya:

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

Dan kemudian pengujian:

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

Setiap kelas yang menunda pembuatan objek ke sub kelasnya untuk objek yang perlu dikerjakan dapat dilihat sebagai contoh pola Pabrik.

Saya telah menyebutkan secara rinci dalam jawaban lain di https://stackoverflow.com/a/49110001/504133

1
nits.kk

Saya menyamakan pabrik dengan konsep perpustakaan. Misalnya Anda dapat memiliki perpustakaan untuk bekerja dengan angka dan yang lain untuk bekerja dengan bentuk. Anda dapat menyimpan fungsi perpustakaan ini dalam direktori yang bernama logis sebagai Numbers atau Shapes. Ini adalah tipe generik yang dapat meliputi bilangan bulat, mengapung, dobules, long atau rectangles, lingkaran, segitiga, pentagon dalam hal bentuk.

Petter pabrik menggunakan polimorfisme, injeksi ketergantungan dan Inversi kontrol.

Tujuan lain dari Pola Pabrik adalah: Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Jadi katakanlah Anda sedang membangun Sistem Operasi atau Kerangka Kerja dan Anda sedang membangun semua komponen diskrit.

Berikut ini adalah contoh sederhana dari konsep Pola Pabrik di PHP. Saya mungkin tidak 100% pada semua itu tetapi dimaksudkan untuk menjadi contoh sederhana. Saya bukan ahli.

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

Kelas pabrik lebih berat, tetapi memberi Anda keuntungan tertentu. Dalam kasus ketika Anda perlu membangun objek Anda dari banyak, sumber data mentah, mereka memungkinkan Anda untuk merangkum hanya logika bangunan (dan mungkin agregasi data) di satu tempat. Di sana dapat diuji secara abstrak tanpa harus peduli dengan antarmuka objek.

Saya telah menemukan ini pola yang berguna, terutama di mana saya tidak dapat mengganti dan ORM tidak memadai dan ingin efisien instantiate banyak objek dari tabel DB bergabung atau prosedur tersimpan.

0
jonfm

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

}
0
Vahe Gharibyan

jika Anda ingin membuat objek yang berbeda dalam hal menggunakan. Ini bermanfaat.

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