Factory dan Singleton Pattern
Factory Pattern • Pattern yang menyediakan template berupa sebuah abstract class untuk penciptaan obyek tanpa menspesifikasikan obyek nyata apa yang akan diciptakan • Tugas subclass adalah menentukan kelas mana yang akan digunakan untuk instansiasi • Class Factory mengijinkan sebuah class melakukan instansiasi pada sub classnya
Studi Kasus 1
Studi Kasus : Pizza! Misal ada method orderPizza, pertama buat Pizza-nya, kemudian sesuaikan pilihan topping pizza:
OrderPizza, beberapa pilihan rasa!
Misal ada 3 pilihan rasa!
OrderPizza bisa bermacam-macam dan berubah-ubah!
clam
pepperoni cheese
greek
vegetable
Ambil semua bagian yang selalu berubah menjadi bagian tersendiri ! (Prinsip Strategy pattern)
Buat menjadi class SimplePizzaFactory
Next: Class toko pizza PizzaStore
Class Diagram
CheesePizza & ClamPizza public class CheesePizza extends Pizza { public CheesePizza() { name = "Cheese Pizza"; dough = "Regular Crust"; sauce = "Marinara Pizza Sauce"; toppings.add("Fresh Mozzarella"); toppings.add("Parmesan"); } } public class ClamPizza extends Pizza { public ClamPizza() { name = "Clam Pizza"; dough = "Thin crust"; sauce = "White garlic sauce"; toppings.add("Clams"); toppings.add("Grated parmesan cheese"); } }
PepperoniPizza & VeggiePizza public class PepperoniPizza extends Pizza { public PepperoniPizza() { name = "Pepperoni Pizza"; dough = "Crust"; sauce = "Marinara sauce"; toppings.add("Sliced Pepperoni"); toppings.add("Sliced Onion"); toppings.add("Grated parmesan cheese"); } } public class VeggiePizza extends Pizza { public VeggiePizza() { name = "Veggie Pizza"; dough = "Crust"; sauce = "Marinara sauce"; toppings.add("Shredded mozzarella"); toppings.add("Grated parmesan"); toppings.add("Diced onion"); toppings.add("Sliced mushrooms"); toppings.add("Sliced red pepper"); toppings.add("Sliced black olives"); } }
Main Class public class PizzaTestDrive { public static void main(String[] args) { SimplePizzaFactory factory = new SimplePizzaFactory(); PizzaStore store = new PizzaStore(factory); Pizza pizza = store.orderPizza("cheese"); System.out.println("We ordered a " + pizza.getName() + "\n"); pizza = store.orderPizza("veggie"); System.out.println("We ordered a " + pizza.getName() + "\n"); } }
Bagaimana jika di franchise?
Factory meperbolehkan subclass untuk memutuskan class yang diinstansiasi!
Jadi • Class PizzaStore menjadi abstract class PizzaStore • Class NYStylePizzaStore extends ke PizzaStore • Class ChicagoStylePizzaStore extends ke PizzaStore • Buat method abstract createPizza di class PizzaStore dan dioverride di class anakanaknya
PizzaStore (updated!) public abstract class PizzaStore { abstract Pizza createPizza(String item); public Pizza orderPizza(String type) { Pizza pizza = createPizza(type); System.out.println("--- Making a " + pizza.getName() + " ---"); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
Sub class decide! • Di dalam method orderPizza, dipanggil method createPizza yang bersifat abstract, sehingga implementasi nya diserahkan ke subclassnya.
• Mana jenis pizza yang dibuat? Disesuaikan dengan jenis pizza yang dijual oleh toko Pizza yang kita pilih! – NYStyle atau ChicagoStyle
NYPizzaStore public class NYPizzaStore extends PizzaStore { Pizza createPizza(String item) { if (item.equals("cheese")) { return new NYStyleCheesePizza(); } else if (item.equals("veggie")) { return new NYStyleVeggiePizza(); } else if (item.equals("clam")) { return new NYStyleClamPizza(); } else if (item.equals("pepperoni")) { return new NYStylePepperoniPizza(); } else return null; } }
ChicagoPizzaStore public class ChicagoPizzaStore extends PizzaStore { Pizza createPizza(String item) { if (item.equals("cheese")) { return new ChicagoStyleCheesePizza(); } else if (item.equals("veggie")) { return new ChicagoStyleVeggiePizza(); } else if (item.equals("clam")) { return new ChicagoStyleClamPizza(); } else if (item.equals("pepperoni")) { return new ChicagoStylePepperoniPizza(); } else return null; } }
Simulasi Pemesanan
Simulasi • Ethan order NYPizza: – PizzaStore nyPizza = new NYPizzaStore();
• Buat Order Pizza: – nyPizzaStore.orderPizza(“cheese”);
• Method orderPizza akan memanggil createPizza – Pizza pizza = createPizza(“cheese”);
• Terakhir kita lakukan: – Prepare(), Bake(), Cut() dan Box()
Kemudian, Pizza • Pizza harus dibuat juga rasa yang berbeda • Ada NYStylePizza dan ChicagoStylePizza!
ChicagoStyleCheesePizza public class ChicagoStyleCheesePizza extends Pizza { public ChicagoStyleCheesePizza() { name = "Chicago Style Deep Dish Cheese Pizza"; dough = "Extra Thick Crust Dough"; sauce = "Plum Tomato Sauce"; toppings.add("Shredded Mozzarella Cheese"); } void cut() { System.out.println("Cutting the pizza into square slices"); } }
NYStyleCheesePizza public class NYStyleCheesePizza extends Pizza { public NYStyleCheesePizza() { name = "NY Style Sauce and Cheese Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; toppings.add("Grated Reggiano Cheese"); } }
TestDrive public class PizzaTestDrive { public static void main(String[] args) { PizzaStore nyStore = new NYPizzaStore(); PizzaStore chicagoStore = new ChicagoPizzaStore(); Pizza pizza = nyStore.orderPizza("cheese"); System.out.println("Ethan ordered a " + pizza.getName() +"\n"); pizza = chicagoStore.orderPizza("cheese"); System.out.println("Joel ordered a " + pizza.getName() + "\n"); } }
Studi Kasus 2
MumeTI Software House • Studi kasus “koneksi database” • Buat koneksi ke Oracle – new OracleConnection();
• Kalau ke SQL Server? – new SqlServerConnection();
• Kalau ke MySQL? – new MySqlConnection();
• Dan lain-lain??? – Access – SQLite
Jika dibuat kodenya if(jenis.equals(“ORACLE”) new OracleConnection(user,pass); else if(jenis.equals(“SQL SERVER”) new SQLServerConnection(user,pass); else new MySqlConnection(user,pass);
Kesalahan • Pertama kita menggunakan keyword new untuk membuat objek, misalnya OracleConnection – suatu class konkret – Membuat berbagai class konkrit => program menjadi besar dan terjadi banyak duplikasi
• Ketiga koneksi di atas dieksekusi dalam main – Padahal bagian-bagian tersebut selalu berubah – Ingat: Open for Extension but closed for modification
• Sebaiknya dibuat class sendiri, pisahkan bagian yang sering berubah! ☺ – Prinsip Strategy Pattern
Ingat prinsip desain buat abstract class Connection
public Connection buatKoneksi(String jenis) { Connection koneksi; if (jenis.equals(“ORACLE”)){ koneksi = new OracleConnection(); } else if (jenis.equals(“SQL Server”)){ koneksi = new SqlServerConnection(); } else { koneksi = new MySqlConnection(); } return koneksi; } Dibuat dalam method tersendiri!
Abstract class Connection public abstract class Connection { String user,pass;
public String description() { return “Generic”; } public abstract void setParams(String username,String password); public abstract int open(); }
public class SqlServerConnection extends Connection { public SqlServerConnection() { } public String description(){ return “SQL Server”; } public void setParams(String username,String password){ user = username; pass = password; } public int open(){ //implement open connection here … } }
public class OracleConnection extends Connection { public OracleConnection() { } public String description(){ return “Oracle Server”; } public void setParams(String username,String password){ user = username; pass = password; } public int open(){ //implement open connection here … } } public class MySqlConnection extends Connection { public MySqlConnection() { } public String description(){ return “MySQL Server”; } public void setParams(String username,String password){ user = username; pass = password; } public int open(){ //implement open connection here … } }
“Class” Factory Pattern public class PolaFactoryKu { private String jenis; public PolaFactoryKu(String j) { jenis = j; } public Connection buatKoneksi() { if (jenis.equals(“Oracle”)){ return new OracleConnection(); } else if (jenis.equals(“SQL Server”)){ return new SqlServerConnection(); } else { return new MySqlConnection(); } } Sudah benar mengembalikan koneksi yang sesuai! }
Penggunaan PolaFactoryKu f; f = new PolaFactoryKu(“Oracle”); Connection connection = f.buatKoneksi(); connection.setParams(“anton”, “rahasia”); connection.open(); System.out.println(“You’re connecting with “ + connection.description()); //dst … f = new PolaFactoryKu(“SQLServer”); Connection connection = f.buatKoneksi(); //dst…
Demo pada VB.NET
Koneksi bisa ke: MySQL, Access, SQLServer, SQLite Nama tabel: mahasiswa Field: nim dan nama
Singleton Pattern
What is Singleton ? • One object of a kind • Ada class yang hanya perlu diinstansiasi 1 kali saja • Alasan: Dalam beberapa kasus hanya dibutuhkan 1 object saja
Like What ? • Database Connection Dalam banyak kasus, koneksi database cukup satu saja Misal : hanya 1 lisensi koneksi
Else ? • Application Setting (Preferences) Beberapa bagian program yang berbeda akan membaca dan menulis setting
More ? • Logging activities Beberapa bagian program perlu menulis ke file log yang sama
Singleton • Memastikan suatu class hanya dapat “menghasilkan” satu object saja • Konsepnya mirip global variable (dengan perbedaan) • Pada Singleton, object hanya dibuat saat dibutuhkan, sedangkan Global Variable dibuat saat awal program dijalankan
public class Whatever { … Bagaimana jika default ? }
Public !
Bagaimana cara membuat object dari class Whatever ? Whatever object1 = new Whatever(); Bisa membuat lebih dari 1 object ? Whatever object1 = new Whatever(); Whatever object2 = new Whatever(); … Whatever object100 = new Whatever();
class Whatever { … dapat diakses dari package yang sama ! Hanya } Tetap bisa dibuat lebih dari 1 object dari class Whatever Whatever object1 = new Whatever(); Whatever object2 = new Whatever(); … Whatever object100 = new Whatever(); Object membutuhkan memory, semakin banyak object ?
Tahukah anda, kita dapat melakukan ini public class Whatever { private Whatever() { } }
Private Constructor ! Apa konsekuensinya ? Hubungannya dengan Singleton ?
Masih ingat konsep static method ? public class Whatever { public static void hitung() { … } } Method hitung() dapat dipanggil tanpa perlu melakukan instansiasi class Whatever
Whatever.hitung();
Bagaimana jika seperti ini ? public class Whatever { public static Whatever getInstance() { … } } Method tersebut mengembalikan object bertipe Whatever
Whatever object1 = Whatever.getInstance();
Kalau ini ? public class Whatever { private Whatever() { } public static Whatever getInstance() { return new Whatever(); } }
Tapi masih bisa membuat lebih dari 1 object !!
Memanggil static method getInstance() merupakan cara alternatif untuk instansiasi
public class Singleton { private static Singleton oneObject; private Singleton() { } //… public static Singleton getInstance() { if(oneObject == null) oneObject = new Singleton(); return oneObject; } //…. }
Sudah cukup? TIDAK !! public static Singleton getInstance() { if(oneObject == null) oneObject = new Singleton(); return oneObject; }
Berpotensi “gagal” jika program kita Multithreading !
Easy Fix ! public static synchronized Whatever getInstance() { if(oneObject == null) oneObject = new Singleton(); return oneObject; }
Cara ini memiliki kelemahan karena synchronized membuat aplikasi anda menjadi lebih lambat !!
Beberapa Pilihan (Multithread) • Tetap gunakan synchronized – Jika proses pembuatan object tidak membutuhkan sumber daya yang besar (waktu dan memory)
• Buat instance sedini mungkin – Dijamin “aman” untuk multithread !
• Lakukan pengecekan “ganda” !
Buat instance sedini mungkin (Thread safe) public class Singleton { private static Singleton oneObject = new Singleton(); private Singleton() { } //… public static Whatever getInstance() { return oneObject; } //…. }
public class Singleton { private volatile static Singleton oneObject; private Singleton() { } //… public static Whatever getInstance() { if(oneObject == null) synchronized(Singleton.class) { if(oneObject == null) { oneObject = new Singleton(); } } } //…. Pengecekan ganda ! }
Class Diagram Singleton
ADA PERTANYAAN ? KONSULTASIKAN KOMPONEN ANDA
SEGERA ☺
NEXT : COMMAND PATTERN