Konstruktor vs Metode Pabrik [ditutup]

181

Saat memodelkan kelas, apa cara yang disukai untuk menginisialisasi:

  1. Konstruktor, atau
  2. Metode Pabrik

Dan apa pertimbangan untuk menggunakan keduanya?

Dalam situasi tertentu, saya lebih suka memiliki metode pabrik yang mengembalikan nol jika objek tidak dapat dibangun. Ini membuat kode rapi. Saya hanya dapat memeriksa apakah nilai yang dikembalikan tidak nol sebelum mengambil tindakan alternatif, berbeda dengan melemparkan pengecualian dari konstruktor. (Saya pribadi tidak suka pengecualian)

Katakanlah, saya memiliki konstruktor pada kelas yang mengharapkan nilai id. Konstruktor menggunakan nilai ini untuk mengisi kelas dari database. Dalam kasus di mana catatan dengan id yang ditentukan tidak ada, konstruktor melempar RecordNotFoundException. Dalam hal ini saya harus menyertakan konstruksi semua kelas tersebut dalam blok try..catch.

Berbeda dengan ini, saya dapat memiliki metode pabrik statis pada kelas-kelas yang akan mengembalikan nol jika catatan tidak ditemukan.

Pendekatan mana yang lebih baik dalam hal ini, konstruktor atau metode pabrik?

Hemanshu Bhojak
sumber

Jawaban:

66

Dari halaman 108 Pola Desain: Elemen Perangkat Lunak Berorientasi Objek yang Dapat Digunakan Kembali oleh Gamma, Helm, Johnson, dan Vlissides.

Gunakan pola Metode Pabrik saat

  • kelas tidak dapat mengantisipasi kelas objek yang harus dibuatnya
  • sebuah kelas menginginkan subclassnya untuk menentukan objek yang dibuatnya
  • kelas mendelegasikan tanggung jawab ke salah satu dari beberapa subclass pembantu, dan Anda ingin melokalkan pengetahuan tentang subclass pembantu mana yang menjadi delegasi
Glenn
sumber
21
Metode pabrik statis berbeda dari pola desain GoF - Factory Method Pattern. stackoverflow.com/questions/929021/…
Sree Rama
Harap jangan dibandingkan dengan pola metode Pabrik dari pola desain GoF.
Sree Rama
137
ini tidak menjelaskan apa
Sushant
@ Sushant, mengapa begitu?
PaulD
2
Jawaban ini tidak menjawab pertanyaan, hanya menyampaikan informasi untuk dibaca untuk memahami / menjelaskan konsep ... Ini lebih dari komentar.
Crt
202

Tanyakan pada diri sendiri apa itu dan mengapa kita memilikinya. Mereka berdua ada di sana untuk membuat instance dari suatu objek.

ElementarySchool school = new ElementarySchool();
ElementarySchool school = SchoolFactory.Construct(); // new ElementarySchool() inside

Tidak ada perbedaan sejauh ini. Sekarang bayangkan bahwa kita memiliki berbagai jenis sekolah dan kita ingin beralih dari menggunakan ElementarySchool ke HighSchool (yang berasal dari ElementarySchool atau mengimplementasikan antarmuka ISchool yang sama dengan ElementarySchool). Perubahan kode adalah:

HighSchool school = new HighSchool();
HighSchool school = SchoolFactory.Construct(); // new HighSchool() inside

Dalam hal antarmuka kita memiliki:

ISchool school = new HighSchool();
ISchool school = SchoolFactory.Construct(); // new HighSchool() inside

Sekarang jika Anda memiliki kode ini di banyak tempat Anda dapat melihat bahwa menggunakan metode pabrik mungkin cukup murah karena setelah Anda mengubah metode pabrik Anda selesai (jika kita menggunakan contoh kedua dengan antarmuka).

Dan inilah perbedaan utama dan keunggulannya. Ketika Anda mulai berurusan dengan hierarki kelas yang kompleks dan Anda ingin secara dinamis membuat instance dari sebuah kelas dari hierarki tersebut, Anda mendapatkan kode berikut. Metode pabrik mungkin mengambil parameter yang memberi tahu metode tersebut contoh konkret yang akan dipakai. Katakanlah Anda memiliki kelas MyStudent dan Anda harus membuat instance objek ISchool yang sesuai sehingga siswa Anda adalah anggota sekolah itu.

ISchool school = SchoolFactory.ConstructForStudent(myStudent);

Sekarang Anda memiliki satu tempat di aplikasi Anda yang berisi logika bisnis yang menentukan objek ISchool mana yang akan dipakai untuk berbagai objek IStudent yang berbeda.

Jadi - untuk kelas sederhana (objek nilai, dll.) Konstruktor baik-baik saja (Anda tidak ingin overengineer aplikasi Anda) tetapi untuk metode pabrik hierarki kelas yang kompleks adalah cara yang disukai.

Dengan cara ini Anda mengikuti prinsip desain pertama dari geng empat buku "Program ke antarmuka, bukan implementasi".

David Pokluda
sumber
2
Bahkan ketika Anda berpikir itu adalah kelas sederhana, ada kemungkinan seseorang perlu memperpanjang kelas sederhana Anda, jadi metode pabrik masih lebih baik. Misalnya Anda dapat mulai dengan ElementarySchool tetapi kemudian seseorang (termasuk Anda) dapat memperpanjangnya dengan PrivateElementarySchool dan PublicElementarySchool.
jack
10
ini harus menjadi jawaban yang diterima
am05mhz
2
@ David, jawaban yang bagus, tetapi dapatkah Anda memperluas contoh di mana setiap implementasi antarmuka mungkin memerlukan parameter berbeda untuk konstruksi. Berikut ini contoh konyol: IFood sandwich = new Sandwich(Cheese chz, Meat meat);dan IFood soup = new Soup(Broth broth, Vegetable veg);Bagaimana pabrik dan atau pembangun dapat membantu di sini?
Brian
1
Saya baru saja membaca tiga penjelasan lain tentang tujuan penggunaan pabrik, dan inilah yang akhirnya "klik" untuk saya. Terima kasih!
Daniel Peirano
Mengapa ini bukan jawaban yang diterima?
Tomas
74

Anda perlu membaca (jika Anda memiliki akses ke) Java 2 Item 1: Pertimbangkan metode pabrik statis daripada konstruktor .

Metode pabrik statis keuntungan:

  1. Mereka punya nama.
  2. Mereka tidak diharuskan membuat objek baru setiap kali dipanggil.
  3. Mereka dapat mengembalikan objek subtipe apa pun dari jenis pengembaliannya.
  4. Mereka mengurangi verbositas membuat instance tipe parameter.

Kerugian metode pabrik statis:

  1. Ketika hanya menyediakan metode pabrik statis, kelas tanpa konstruktor publik atau yang dilindungi tidak dapat disubklasifikasikan.
  2. Mereka tidak mudah dibedakan dari metode statis lainnya
cherouvim
sumber
4
Menurut saya ini agak bug yang parah di Jawa, maka masalah OOD umum. Ada banyak bahasa OO yang bahkan tidak memiliki konstruktor, namun subclass berfungsi dengan baik.
Jörg W Mittag
1
@cherouvim mengapa sebagian besar kode ditulis menggunakan Konstruktor jika( factory methods are better than Constructors. ( Item-1 ) ) Effective java
Asif Mushtaq
Poin bagus. Ini khusus Java. Kasing dapat dibuat untuk fitur bahasa yang membuat metode pabrik dapat dibedakan dari metode statis lainnya.
OCDev
30

Secara default, konstruktor harus lebih disukai, karena mereka lebih mudah dimengerti dan ditulis. Namun, jika Anda secara khusus perlu memisahkan sifat konstruksi suatu objek dari makna semantiknya sebagaimana dipahami oleh kode klien, Anda sebaiknya menggunakan pabrik.

Perbedaan antara konstruktor dan pabrik adalah analog dengan, katakanlah, variabel dan pointer ke variabel. Ada tingkat tipuan lain, yang merupakan kerugian; tetapi ada tingkat fleksibilitas lain juga, yang merupakan keuntungan. Jadi saat membuat pilihan, Anda sebaiknya disarankan melakukan analisis biaya versus manfaat ini.

Frederick The Fool
sumber
17
Jadi, (gaya TDD) Anda akan mulai dengan konstruktor sebagai cara paling sederhana untuk menyelesaikan pekerjaan. Dan kemudian refactor ke pabrik setelah Anda mulai mendapatkan bau kode (seperti logika kondisional berulang yang menentukan konstruktor untuk memanggil)?
AndyM
1
Poin yang sangat penting. Sebuah studi pengguna membandingkan pabrik dan konstruktor menemukan hasil yang sangat signifikan yang menunjukkan bahwa pabrik merugikan kegunaan API: "pengguna memerlukan waktu lebih banyak (p = 0,005) untuk membangun objek dengan pabrik daripada dengan konstruktor" [Pola Pabrik dalam Desain API : Evaluasi Kegunaan ].
mdeff
12

Gunakan pabrik hanya ketika Anda membutuhkan kontrol ekstra dengan pembuatan objek, dengan cara yang tidak dapat dilakukan dengan konstruktor.

Pabrik memiliki kemungkinan caching misalnya.

Cara lain untuk menggunakan pabrik adalah dalam skenario di mana Anda tidak tahu jenis yang ingin Anda bangun. Seringkali Anda melihat jenis penggunaan ini dalam skenario pabrik plugin, di mana setiap plugin harus berasal dari baseclass atau mengimplementasikan beberapa jenis antarmuka. Pabrik membuat instance kelas yang berasal dari baseclass atau yang mengimplementasikan antarmuka.

Patrick Peters
sumber
11

Sebuah kutipan dari "Java Efektif", edisi ke-2, Butir 1: Pertimbangkan metode pabrik statis alih-alih konstruktor, hal. 5:

"Perhatikan bahwa metode pabrik statis tidak sama dengan pola Metode Pabrik dari Pola Desain [Gamma95, hal. 107]. Metode pabrik statis yang dijelaskan dalam item ini tidak memiliki padanan langsung dalam Pola Desain."

Eugen Labun
sumber
10

Selain "java efektif" (seperti yang disebutkan dalam jawaban lain), buku klasik lain juga menyarankan:

Lebih suka metode pabrik statis (dengan nama yang menggambarkan argumen) ke konstruktor kelebihan beban.

Misalnya. jangan menulis

Complex complex = new Complex(23.0);

melainkan menulis

Complex complex = Complex.fromRealNumber(23.0);

Buku ini sejauh menyarankan untuk membuat Complex(float) konstruktor pribadi, untuk memaksa pengguna untuk memanggil metode pabrik statis.

blue_note
sumber
2
Membaca bagian buku itu membawaku ke sini
Purple Haze
1
@Bayrem: saya juga, saya membaca ulang baru-baru ini dan berpikir saya harus menambahkannya ke jawaban.
blue_note
1
Pada catatan terkait, Anda mungkin menemukan membantu beberapa konvensi penamaan bekerja dengan java.time kerangka mengenai penamaan from…, to…, parse…, with…, dan sebagainya. Perlu diingat bahwa kelas java.time dibangun agar tidak berubah, tetapi beberapa konvensi penamaan ini mungkin berguna untuk diikuti dengan kelas yang bisa berubah juga.
Basil Bourque
7

Contoh nyata dari aplikasi CAD / CAM.

Jalur pemotongan akan dibuat dengan menggunakan konstruktor. Ini adalah serangkaian garis dan busur yang mendefinisikan jalur untuk memotong. Sementara rangkaian garis dan busur dapat berbeda dan memiliki koordinat yang berbeda dengan mudah ditangani dengan meneruskan daftar ke konstruktor.

Suatu bentuk akan dibuat dengan menggunakan pabrik. Karena meskipun ada kelas bentuk, setiap bentuk akan diatur berbeda tergantung pada jenis bentuknya. Kami tidak tahu bentuk apa yang akan kami inisialisasi hingga pengguna membuat pilihan.

RS Conley
sumber
5

Katakanlah, saya memiliki konstruktor pada kelas yang mengharapkan nilai id. Konstruktor menggunakan nilai ini untuk mengisi kelas dari database.

Proses ini tentunya harus di luar konstruktor.

  1. Konstruktor tidak boleh mengakses database.

  2. Tugas dan alasan konstruktor adalah menginisialisasi anggota data dan menetapkan kelas invarian menggunakan nilai yang diteruskan ke konstruktor.

  3. Untuk yang lainnya pendekatan yang lebih baik adalah menggunakan metode pabrik statis atau dalam kasus yang lebih kompleks kelas pabrik atau pembangun yang terpisah .

Beberapa garis panduan konstruktor dari Microsoft :

Lakukan pekerjaan minimal di konstruktor. Konstruktor seharusnya tidak melakukan banyak pekerjaan selain untuk menangkap parameter konstruktor. Biaya pemrosesan lain harus ditunda sampai diperlukan.

Dan

Pertimbangkan menggunakan metode pabrik statis daripada konstruktor jika semantik operasi yang diinginkan tidak memetakan langsung ke konstruksi contoh baru.

Lightman
sumber
2

Terkadang Anda harus memeriksa / menghitung beberapa nilai / kondisi saat membuat objek. Dan jika itu dapat membuang Exception - constructro adalah cara yang sangat buruk. Jadi, Anda perlu melakukan sesuatu seperti ini:

var value = new Instance(1, 2).init()
public function init() {
    try {
        doSome()
    }
    catch (e) {
        soAnotherSome()
    }
}

Di mana semua perhitungan tambahan ada di init (). Tetapi hanya Anda sebagai pengembang yang benar-benar tahu tentang init ini (). Dan tentu saja, setelah berbulan-bulan Anda hanya melupakannya. Tetapi jika Anda memiliki pabrik - cukup lakukan semua yang Anda perlukan dalam satu metode dengan menyembunyikan init ini () dari panggilan langsung - jadi tidak ada masalah. Dengan pendekatan ini tidak ada masalah dengan jatuh pada penciptaan dan kebocoran memori.

Seseorang memberi tahu Anda tentang caching. Ini baik. Tetapi Anda juga harus ingat tentang pola Flyweight yang bagus untuk digunakan dengan cara Factory.

trashgenerator
sumber