Halo! Hari ini kita akan terus mempelajari pola desain dan membicarakan metode pabrik (FactoryMethod). Anda akan mengetahui apa itu dan tugas apa yang cocok untuk template ini. Kita akan melihat pola desain ini dalam praktiknya dan mengeksplorasi strukturnya. Untuk memperjelas semua hal di atas, Anda perlu memahami topik berikut:
- Warisan di Jawa.
- Metode dan kelas abstrak di Java.
Masalah apa yang dipecahkan oleh metode pabrik?
Dalam semua pola desain pabrik, ada dua kelompok peserta – pencipta (pabrik itu sendiri) dan produk (objek yang dibuat oleh pabrik). Bayangkan situasinya: kita memiliki pabrik yang memproduksi mobil dengan merek AutoRush. Dia tahu cara membuat model mobil dengan tipe bodi berbeda:- sedan
- station wagon
- mobil tertutup berpintu dua
- Sedan AutoRush
- Gerobak stasiun AutoRush
- coupe AutoRush
- Sedan OneAuto
- Gerobak stasiun OneAuto
- coupe OneAuto
Sedikit tentang template pabrik
Izinkan saya mengingatkan Anda: kami membangun kedai kopi virtual kecil bersama Anda. Di dalamnya, kami belajar cara membuat berbagai jenis kopi dengan menggunakan pabrik sederhana. Hari ini kita akan menyempurnakan contoh ini. Mari kita ingat seperti apa kedai kopi kita yang pabriknya sederhana. Kami mengadakan kelas kopi:
public class Coffee {
public void grindCoffee(){
// перемалываем кофе
}
public void makeCoffee(){
// делаем кофе
}
public void pourIntoCup(){
// наливаем в чашку
}
}
Dan juga beberapa ahli warisnya - jenis kopi tertentu yang dapat diproduksi oleh pabrik kami:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Untuk kenyamanan menerima pesanan, kami telah memperkenalkan transfer:
public enum CoffeeType {
ESPRESSO,
AMERICANO,
CAFFE_LATTE,
CAPPUCCINO
}
Pabrik kopinya sendiri terlihat seperti ini:
public class SimpleCoffeeFactory {
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new Americano();
break;
case ESPRESSO:
coffee = new Espresso();
break;
case CAPPUCCINO:
coffee = new Cappuccino();
break;
case CAFFE_LATTE:
coffee = new CaffeLatte();
break;
}
return coffee;
}
}
Dan terakhir, kedai kopi itu sendiri:
public class CoffeeShop {
private final SimpleCoffeeFactory coffeeFactory;
public CoffeeShop(SimpleCoffeeFactory coffeeFactory) {
this.coffeeFactory = coffeeFactory;
}
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
return coffee;
}
}
Modernisasi pabrik sederhana
Kedai kopi kami berjalan dengan baik. Sedemikian rupa sehingga kami berpikir untuk memperluas. Kami ingin membuka beberapa poin baru. Sebagai orang yang giat, kami tidak akan membuat kedai kopi yang monoton. Saya ingin masing-masing memiliki twistnya sendiri. Oleh karena itu, untuk memulainya, kami akan membuka dua poin: dalam gaya Italia dan Amerika. Perubahan tersebut tidak hanya mempengaruhi interior, tetapi juga minuman:- di kedai kopi Italia kami akan menggunakan merek kopi eksklusif Italia, dengan penggilingan dan pemanggangan khusus.
- Porsi Amerika akan sedikit lebih besar, dan setiap pesanan kami akan menyajikan marshmallow leleh - marshmallow.
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Dan itu menjadi 8:
public class ItalianStyleAmericano extends Coffee {}
public class ItalianStyleCappucino extends Coffee {}
public class ItalianStyleCaffeLatte extends Coffee {}
public class ItalianStyleEspresso extends Coffee {}
public class AmericanStyleAmericano extends Coffee {}
public class AmericanStyleCappucino extends Coffee {}
public class AmericanStyleCaffeLatte extends Coffee {}
public class AmericanStyleEspresso extends Coffee {}
Karena kami ingin model bisnis saat ini tidak berubah, kami ingin metode ini orderCoffee(CoffeeType type)
mengalami sedikit perubahan. Mari kita lihat:
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
return coffee;
}
Pilihan apa yang kita punya? Kita sudah tahu cara menulis pabrik kan? Hal paling sederhana yang langsung terlintas dalam pikiran adalah menulis dua pabrik serupa, dan kemudian meneruskan implementasi yang diperlukan ke kedai kopi kita di konstruktor. Maka kelas kedai kopi tersebut tidak akan berubah. Pertama, kita perlu membuat kelas pabrik baru, mewarisi dari pabrik sederhana kita dan mengganti kelas createCoffee (CoffeeType type)
. Mari kita tulis pabrik untuk membuat kopi dengan gaya Italia dan Amerika:
public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory{
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
Sekarang kita dapat meneruskan implementasi pabrik yang diperlukan ke CoffeeShop. Mari kita lihat seperti apa kode untuk memesan kopi dari kedai kopi yang berbeda. Misalnya, cappuccino gaya Italia dan Amerika:
public class Main {
public static void main(String[] args) {
/*
Закажем капучино в итальянском стиле:
1. Создадим фабрику для приготовления итальянского кофе
2. Создадим новую кофейню, передав ей в конструкторе фабрику итальянского кофе
3. Закажем наш кофе
*/
SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
/*
Закажем капучино в американском стиле
1. Создадим фабрику для приготовления американского кофе
2. Создадим новую кофейню, передав ей в конструкторе фабрику американского кофе
3. Закажем наш кофе
*/
SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
}
}
Kami membuat dua kedai kopi berbeda, memindahkan masing-masing ke pabrik yang dibutuhkan. Di satu sisi, kami telah mencapai tujuan kami, tetapi di sisi lain... Ada sesuatu yang menggores jiwa pengusaha yang tak tertahankan... Mari kita cari tahu apa yang salah. Pertama, banyaknya pabrik. Apakah mungkin untuk membuat pabrik Anda sendiri setiap saat untuk titik baru dan, sebagai tambahan, memastikan bahwa saat membuat kedai kopi, pabrik yang diperlukan dipindahkan ke konstruktor? Kedua, masih berupa pabrik sederhana. Hanya sedikit dimodernisasi. Kami masih mempelajari pola baru di sini. Ketiga, apakah mungkin untuk melakukannya secara berbeda? Akan sangat bagus jika kita dapat melokalisasi semua pertanyaan tentang membuat kopi di dalam kelas CoffeeShop
, menghubungkan proses pembuatan kopi dan melayani pesanan, namun pada saat yang sama menjaga fleksibilitas yang cukup untuk membuat kopi dengan gaya yang berbeda. Jawabannya adalah ya, Anda bisa. Ini disebut pola desain metode pabrik.
Dari metode pabrik sederhana hingga metode pabrik
Untuk memecahkan masalah seefisien mungkin, kami:- Mari kita kembalikan metodenya
createCoffee(CoffeeType type)
ke kelasCoffeeShop
. - Mari kita jadikan metode ini abstrak.
- Kelas itu sendiri
CoffeeShop
akan menjadi abstrak. - Kelas tersebut
CoffeeShop
akan mempunyai ahli waris.
CoffeeShop
yang menerapkan metode createCoffee(CoffeeType type)
sesuai dengan tradisi terbaik barista Italia. Jadi, secara berurutan. Langkah 1. Mari kita membuat kelas menjadi Coffee
abstrak. Kami sekarang memiliki dua keluarga produk yang berbeda. Minuman kopi Italia dan Amerika masih memiliki nenek moyang yang sama: Coffee
. Akan benar jika menjadikannya abstrak:
public abstract class Coffee {
public void makeCoffee(){
// делаем кофе
}
public void pourIntoCup(){
// наливаем в чашку
}
}
Langkah 2. Jadikan CoffeeShop
abstrak, dengan metode abstrakcreateCoffee(CoffeeType type)
public abstract class CoffeeShop {
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = createCoffee(type);
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
return coffee;
}
protected abstract Coffee createCoffee(CoffeeType type);
}
Langkah 3. Buat kedai kopi Italia, kelas turunan dari kedai kopi abstrak. Di dalamnya kami menerapkan metode createCoffee(CoffeeType type)
dengan mempertimbangkan spesifikasi Italia.
public class ItalianCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
Langkah 4. Mari kita lakukan hal yang sama untuk kedai kopi bergaya Amerika.
public class AmericanCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
Langkah 5. Mari kita lihat seperti apa bentuk pemesanan latte ala Amerika dan Italia:
public class Main {
public static void main(String[] args) {
CoffeeShop italianCoffeeShop = new ItalianCoffeeShop();
italianCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
CoffeeShop americanCoffeeShop = new AmericanCoffeeShop();
americanCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
}
}
Selamat. Kami baru saja menerapkan pola desain metode pabrik di kedai kopi kami.
Cara kerja metode pabrik
Sekarang mari kita lihat lebih dekat apa yang kita dapatkan. Diagram di bawah menunjukkan kelas yang dihasilkan. Blok hijau adalah kelas pencipta, blok biru adalah kelas produk. Kesimpulan apa yang bisa diambil?- Semua produk merupakan implementasi dari kelas abstrak
Coffee
. - Semua pencipta adalah implementasi dari kelas abstrak
CoffeeShop
. - Kami mengamati dua hierarki kelas paralel:
- Hirarki produk. Kita melihat keturunan Italia dan keturunan Amerika
- Hirarki pencipta. Kita melihat keturunan Italia dan keturunan Amerika
- Superclass
CoffeeShop
tidak memiliki informasi tentang implementasi produk spesifik mana (Coffee
) yang akan dibuat. - Superclass
CoffeeShop
mendelegasikan pembuatan produk tertentu kepada turunannya. - Setiap kelas turunan
CoffeeShop
mengimplementasikan metode pabrikcreateCoffee()
sesuai dengan spesifikasinya. Dengan kata lain, dalam implementasi kelas pencipta, keputusan dibuat untuk menyiapkan produk tertentu berdasarkan spesifikasi kelas pencipta.
Struktur metode pabrik
Diagram di atas menunjukkan struktur umum pola metode pabrik. Apa lagi yang penting di sini?- Kelas Creator berisi implementasi semua metode yang berinteraksi dengan produk, kecuali metode pabrik.
- Metode abstrak
factoryMethod()
harus diimplementasikan oleh semua turunan kelasCreator
. - Kelas
ConcreteCreator
mengimplementasikan metodefactoryMethod()
yang secara langsung menghasilkan suatu produk. - Kelas ini bertanggung jawab untuk menciptakan produk tertentu. Ini adalah satu-satunya kelas yang memiliki informasi tentang pembuatan produk ini.
- Semua produk harus mengimplementasikan antarmuka yang sama - menjadi turunan dari kelas produk yang sama. Hal ini diperlukan agar kelas yang menggunakan produk dapat mengoperasikannya pada tingkat abstraksi daripada implementasi konkrit.
GO TO FULL VERSION