Top Banner
Catatan Interpreting Design Pattern by. Ahmad Hidayat Sumber: http://www.oodesign.com I. Design Principles I.1 Pendahuluan I.1.1 Apa itu Software Design Principles? Software design principles merupakan kumpulan pedoman yang membantu kita untuk menghindari desain yang buruk. Prinsip-prinsip desain yang berhubungan dalam buku Robert Martin yang berjudul "Agile Software Development: Principles, Patterns, and Practices". Terdapat 3 karakteristik penting dari desain yang buruk yang harus dihindari : 1. Rigidity (Kekakuan). Sulit untuk melakukan perubahan karena setiap perubahan terlalu banyak mempengaruhi bagian lain dari sistem. 2. Fragility (kerapuhan). Ketika melakukan perubahan, dapat membuat terhentinya bagian dari sistem yang tidak kita duga. 3. Immobility. Sulit untuk digunakan kembali dalam aplikasi lain karena tidak bisa diuraikan dari aplikasi yang bersangkutan. I.1.2 Open Close Principle Software entitas seperti class , modul dan fungsi harus terbuka untuk ekstensi (digunakan jangka panjang, by Yayat) tapi ditutup untuk modifikasi. OPC adalah prinsip generik. Anda dapat mempertimbangkan hal itu ketika menulis class Anda untuk memastikan bahwa ketika Anda perlu untuk memperpanjang perilaku mereka Anda tidak harus mengubah class namun untuk memperpanjang itu. Prinsip yang sama dapat diterapkan untuk modul, paket, perpustakaan. Jika Anda memiliki sebuah perpustakaan yang berisi satu set class ada banyak
143

Catatan Design Pattern by Ahmad Hidayat

Nov 30, 2015

Download

Documents

ahmad hidayat

catatan yayat 089667524989
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Catatan Design Pattern by Ahmad Hidayat

Catatan Interpreting Design Pattern by. Ahmad HidayatSumber: http://www.oodesign.com

I. Design PrinciplesI.1 Pendahuluan

I.1.1 Apa itu Software Design Principles?Software design principles merupakan kumpulan pedoman yang membantu kita untuk menghindari desain yang buruk. Prinsip-prinsip desain yang berhubungan dalam buku Robert Martin yang berjudul "Agile Software Development: Principles, Patterns, and Practices". Terdapat 3 karakteristik penting dari desain yang buruk yang harus dihindari :1. Rigidity (Kekakuan). Sulit untuk melakukan perubahan karena setiap

perubahan terlalu banyak mempengaruhi bagian lain dari sistem.2. Fragility (kerapuhan). Ketika melakukan perubahan, dapat membuat

terhentinya bagian dari sistem yang tidak kita duga.3. Immobility. Sulit untuk digunakan kembali dalam aplikasi lain karena tidak

bisa diuraikan dari aplikasi yang bersangkutan.

I.1.2 Open Close Principle Software entitas seperti class, modul dan fungsi harus terbuka untuk

ekstensi (digunakan jangka panjang, by Yayat) tapi ditutup untuk modifikasi.

OPC adalah prinsip generik. Anda dapat mempertimbangkan hal itu ketika menulis class Anda untuk memastikan bahwa ketika Anda perlu untuk memperpanjang perilaku mereka Anda tidak harus mengubah class namun untuk memperpanjang itu. Prinsip yang sama dapat diterapkan untuk modul, paket, perpustakaan. Jika Anda memiliki sebuah perpustakaan yang berisi satu set class ada banyak alasan yang membuat Anda lebih memilih untuk memperpanjang tanpa mengubah kode yang sudah ditulis (kompatibilitas, pengujian regresi). Ini sebabnya mengapa kita harus memastikan modul kita mengikuti Prinsip Buka Tutup (Open Close Principle).

Ketika mengacu pada class, Open Close Principle dapat dipastikan dengan menggunakan abstract class dan concrete classes untuk menerapkan perilakunya. Ini akan membuat kita memiliki concrete classes untuk memperluas abstract class bukan mengubah abstract class. Contoh kasusnya adalah Template Pattern dan Strategy Pattern.

I.1.3 Dependency Inversion Principle Modul High-level tidak harus bergantung pada modul Low-level.

Keduanya harus bergantung pada abstraksi.

Page 2: Catatan Design Pattern by Ahmad Hidayat

Abstraksi tidak harus tergantung pada detail. Detail harus bergantung pada abstraksi.

Dependency Inversion Principle menyatakan bahwa kita harus memisahkan modul High-level dari modul Low-level, memasukan abstraction layer di antara high level classes dan low level classes. Lebih jauh lagi tentang membalikkan ketergantungan (inverts the dependency) : daripada pada kita menulis abstraksi didasarkan pada rincian, lebih baik menulis rincian berdasarkan abstraksi.Ketergantungan Inversi atau Pembalikan dari Control (Dependency Inversion or Inversion of Control) lebih mengacu pada istilah suatu cara di mana dependensi terealisasi. Dengan cara klasik ketika software module (class, framework, dll) membutuhkan beberapa modul lain, dilakukan inisialisasi dan memegang direct reference. Ini akan membuat 2 modul yang sukar digabungkan. Dalam rangka untuk memisahkan mereka modul pertama akan memberikan sangkutan (hook) (seperti properti, parameter dll) dan sebuah modul eksternal mengontrol dependensi akan menyuntikkan (injeksi) referensi untuk yang kedua..Dengan menerapkan Dependency Inversion (Inversi Ketergantungan), suatu modul dapat dengan mudah diubah oleh modul lain hanya dengan mengubah modul ketergantungan. Factories and Abstract Factorie dapat digunakan sebagai dependency frameworks (framework kerja ketergantungan), tetapi ada framworks khusus untuk itu, yang dikenal sebagai Inversion of Control Container.

I.1.4 Interface Segregation Principle Clients tidak boleh dipaksa untuk bergantung pada interfaces yang

tidak digunakan.Prinsip ini mengajarkan kita untuk berhati-hati bagaimana kita membuat interface. Ketika kita membuat interface, kita harus berhati-hati untuk hanya menambahkan metode yang harus ada. Jika kita menambahkan metode di dalam interface yang seharusnya tidak ada class yang mengimplementasikan interface dengan menerapkan metodenya. Sebagai contoh jika kita membuat sebuah interface yang disebut Pekerja dan menambahkan metode istirahat makan siang, semua pekerja harus menerapkannya. Bagaimana jika pekerja adalah robot?Sebagai kesimpulan interface yang berisi metode yang tidak spesifik seperti di atas disebut interface tercemar. Kita harus menghindarinya.

I.1.5 Single Responsibility Principle Sebuah class hanya memiliki satu alasan untuk berubah.Dalam konteks ini tanggung jawab (responsibility) ini dianggap sebagai satu-satunya alasan untuk berubah. Prinsip ini menyatakan bahwa jika kita memiliki 2 alasan untuk mengubah satu class, kita harus membagi fungsi dalam dua class. Setiap class hanya akan menangani satu tanggung jawab dan jika kemudian hari kita perlu membuat satu perubahan kita akan membuatnya dalam class yang menanganinya. Ketika kita perlu melakukan

Page 3: Catatan Design Pattern by Ahmad Hidayat

perubahan dalam class yang memiliki tanggung jawab yang lebih dari satu fungsi, hal ini dapat mempengaruhi fungsi lainya.Single Responsibility Principle diperkenalkan Tom DeMarco dalam bukunya yang berjudul Structured Analysis and Systems Specification, 1979. Robert Martin menafsirkan kembali konsep dan menegaskan tanggung jawab (responsibility) sebagai satu alasan untuk berubah.

I.1.6 Liskov's Substitution Principle Tipe turunan harus benar-benar dapat menggantikan basis atau

induknya.Prinsip ini hanyalah kelanjutan dari Open Close Principle dalam hal behavior, bahwa kita harus memastikan class turunan memperpanjang class dasar atau induk tanpa mengubah behaviornya. Class-class turunan yang baru harus mampu menggantikan class induk tanpa perubahan kode.Prinsip Pergantian Liskov yang diperkenalkan oleh Barbara Liskov dalam Konferensi 1987 pada Aplikasi dan Sistem Bahasa Pemrograman Berorientasi Obyek, dalam abstraksi dan hirarki data.

I.2 Pembahasan Lebih DalamI.2.1 Open Close Principle

Motivasi

Sebuah desain aplikasi dan impelentasi kode yang pandai harus memperhatikan frekuensi perubahan yang sering dilakukan selama fase pengembangan dan pemeliharaan aplikasi. Biasanya, banyak perubahan ketika sebuah fungsi baru ditambahkan ke aplikasi. Perubahan-perubahan dalam kode yang sudah ada harus diminimalkan, karena telah diasumsikan bahwa kode yang ada sudah dilakukan unit test dan perubahan kode yang sudah ditulis dapat mempengaruhi fungsi yang ada yang tidak diinginkan.

Page 4: Catatan Design Pattern by Ahmad Hidayat

Open Close Principle menyatakan bahwa desain dan penulisan kode harus dilakukan untuk meminimalisasi perubahan kode yang sudah ada ketika fungsi baru harus ditambahkan. Desain harus dilakukan untuk memungkinkan penambahan fungsi baru sebagai class baru, menjaga sebanyak mungkin kode yang ada tidak berubah.

Maksud

Software entities seperti classes, modules dan functions harus terbuka untuk diperluas, tapi tertutup untuk modifikasi .

Contoh

Di bawah ini adalah contoh yang melanggar Open Close Principle. Implementasi sebuah editor grafis yang dapat menggambar dengan berbagai bentuk. Ini jelas bahwa ia tidak mengikuti Open Close Principle sejak class GraphicEditor harus dimodifikasi untuk setiap class bentuk baru yang harus ditambahkan. Ada beberapa kelemahan:1. Untuk setiap penambahan bentuk baru, pengujian unit GraphicEditor

harus diulang.2. Ketika jenis bentuk baru ditambahkan waktu untuk menambahkan hal

itu akan menjadi tinggi karena pengembang yang menambahkannya harus memahami logika GraphicEditor tersebut.

3. Menambahkan bentuk baru dapat mempengaruhi fungsi yang ada dengan cara yang tidak diinginkan, bahkan jika bentuk baru bekerja sempurna

Dalam rangka untuk memiliki efek yang lebih dramatis, bayangkan bahwa Editor Grafis adalah class besar, dengan banyak fungsi di dalamnya, ditulis dan diubah oleh banyak pengembang, sementara bentuknya (shape) mungkin class yang diimplementasikan hanya oleh satu pengembang. Dalam hal ini akan menjadi perbaikan besar untuk memungkinkan penambahan bentuk (shape) baru tanpa mengubah class GraphicEditor.

// Open-Close Principle - Bad example

Page 5: Catatan Design Pattern by Ahmad Hidayat

class GraphicEditor { public void drawShape(Shape s) { if (s.m_type==1) drawRectangle(s); else if (s.m_type==2) drawCircle(s); } public void drawCircle(Circle r) {....} public void drawRectangle(Rectangle r) {....} } class Shape { int m_type; } class Rectangle extends Shape { Rectangle() { super.m_type=1; } } class Circle extends Shape { Circle() { super.m_type=2; } }

Di bawah ini adalah contoh yang mendukung Open Close Principle. Dalam desain baru kita menggunakan metode abstract draw() dalam GraphicEditor untuk menggambar objek, sampai berpindah implementasinya di concrete shape objects (bentuk). Menggunakan Open Close Principle masalah dari desain sebelumnya sudah dihindari, karena GraphicEditor tidak berubah ketika class shape baru ditambahkan:

Tidak diperlukan unit testing. Tidak perlu memahami kode sumber dari GraphicEditor. Karena kode drawing telah dipindahkan ke concrete shape classes, itu

menurunkan risiko untuk mempengaruhi functionallity yang sudah ada ketika functionallity baru ditambahkan.

Page 6: Catatan Design Pattern by Ahmad Hidayat

// Open-Close Principle - Good example class GraphicEditor { public void drawShape(Shape s) { s.draw(); } } class Shape { abstract void draw(); } class Rectangle extends Shape { public void draw() { // draw the rectangle } }

Kesimpulan

Prinsip OCP hanyalah sebuah prinsip. Membuat desain yang fleksibel melibatkan tambahan waktu dan usaha yang dihabiskan untuk itu dan memperkenalkan tingkat baru abstraksi meningkatkan kompleksitas kode. Jadi prinsip ini harus diterapkan pada area yang paling mungkin untuk diubah.

Ada banyak design patterns yang membantu kita untuk memperluas kode tanpa mengubahnya. Misalnya Decorator pattern membantu kita untuk mengikuti Open Close Principle. Juga Metode Factory atau Observer pattern dapat digunakan untuk merancang suatu aplikasi yang mudah untuk berubah dengan perubahan minimal dalam kode yang sudah ada.

Page 7: Catatan Design Pattern by Ahmad Hidayat

I.2.2 Dependency Inversion Principle

Motivasi

Dalam sebuah aplikasi kita memiliki low level class yang melaksanakan operasi utama dan dasar, dan high level class yang merangkum (encapsulate) logika yang kompleks dan bergantung pada low level class. Sebuah cara alami menerapkan struktur seperti ini adalah kita menulis low level class, kemudian kita punya low level class untuk menulis high level class yang kompleks. Sejak high level class di dalam terminologi ini , kita terlihat sudah melakukan hal yang logis. Tapi ini bukan desain yang fleksibel. Apa yang terjadi jika kita perlu mengganti low level class?

Mari kita ambil contoh klasik dari copy module yang membaca karakter dari keyboard dan mencetak ke perangkat printer. High level class yang mengandung logika adalah class Copy. Low level class adalah KeyboardReader dan PrinterWriter.

Dalam desain yang buruk high level class menggunakan langsung low level class. Dalam hal ini jika kita ingin mengubah desain untuk mengarahkan output ke class FileWriter baru, kita harus mengubah class Salin. (Mari kita asumsikan bahwa itu adalah class yang sangat kompleks, dengan banyak logika dan benar-benar sulit untuk diuji).

Untuk menghindari masalah tersebut kita dapat menggunakan abstraction layer di antara high level class dan low level class. Karena high level modules berisi logika yang kompleks mereka tidak harus bergantung pada low level modules dan abstraction layer baru tidak harus dibuat berdasarkan low level modules. Low level modules dibuat berdasarkan abstraction layer.

Menurut prinsip ini cara merancang struktur class adalah mulai dari high level class ke low level modules: High Level Classes --> Abstraction Layer --> Low Level Classes

Maksud

high level modules tidak harus bergantung pada high level modules. Keduanya harus bergantung pada abstraksi.

Abstraksi tidak harus tergantung pada rincian. Rincian harus bergantung pada abstraksi.

Page 8: Catatan Design Pattern by Ahmad Hidayat

Contoh

Di bawah ini adalah contoh yang melanggar Dependency Inversion Principle. Kita memiliki class Manager yang merupakan high level class, dan Worker yang merupakan low level class. Kita perlu menambahkan modul baru untuk aplikasi kita karena di perusahaan ada beberapa pekerja khusus yang baru dipekerjakan. Kita membuat class baru SuperWorker untuk ini.

Mari kita berasumsi bahwa class Manager itu kompleks yang mengandung logika sangat kompleks. Dan sekarang kita harus mengubahnya dalam rangka menambahkan class baru yaitu SuperWorker. Mari kita lihat kelemahanya: Kita harus mengubah class Manager (ingat itu adalah sesuatu yang

kompleks dan ini akan membutuhkan banyak waktu dan usaha). Beberapa fungsi yang sudah ada di class Manager mungkin akan

terpengaruh. Unit testing harus diulang.

Semua masalah tersebut akan membutuhkan banyak waktu untuk menyelesaikanya. Akan lebih sederhana jika aplikasi ini dirancang mengikuti Dependency Inversion Principle. Untuk itu kita membuat class Manager, sebuah interface IWorker dan class Worker implementasi dari interface IWorker. Ketika kita perlu menambahkan class SuperWorker yang harus kita lakukan adalah mengimplementasikan interface IWorker untuk itu.

// Dependency Inversion Principle - Bad exampleclass Worker {

public void work() {// ....working

}}class Manager {

Worker m_worker;

public void setWorker(Worker w) {m_worker=w;

}public void manage() {

m_worker.work();}

}class SuperWorker {

public void work() {//.... working much more

}}

Page 9: Catatan Design Pattern by Ahmad Hidayat

Berikut ini adalah kode yang mendukung Dependency Inversion Principle. Dalam desain baru ini layer abstraction baru ditambahkan melalui Interface IWorker. Sekarang masalah dari kode di atas sudah diselesaikan: Class Manager tidak boleh diubah. Mengurangi resiko untuk mempengaruhi fungsionalitas yang sudah ada

di class Manager. Tidak perlu mengulangi unit testing untuk class Manager.

// Dependency Inversion Principle - Good exampleinterface IWorker {

public void work();}

class Worker implements IWorker{public void work() {

// ....working}

}

class SuperWorker implements IWorker{public void work() {

//.... working much more}

}

class Manager {IWorker m_worker;

public void setWorker(IWorker w) {m_worker=w;

}

public void manage() {m_worker.work();

}}

Kesimpulan

Bila prinsip ini diterapkan, itu berarti high level class tidak bekerja secara langsung dengan class low level classes, tapi menggunakan interface sebagai abstract layer. Dalam kasus kreasi dalam membuat baru low level objects di dalam high level classes (jika perlukan) tidak dapat dilakukan dengan menggunakan operator new. Untuk itu, beberapa Creational design pattern dapat digunakan, seperti Factory Method, Abstract Factory, Prototype.

Page 10: Catatan Design Pattern by Ahmad Hidayat

Template Design Pattern adalah contoh di mana prinsip DIP diterapkan.

Tentu saja, dengan menggunakan prinsip ini menyiratkan upaya peningkatan dan kode yang lebih kompleks, tetapi lebih fleksibel. Prinsip ini tidak dapat diterapkan untuk setiap class atau setiap modul. Jika kita memiliki fungsi class yang lebih mungkin untuk tetap tidak berubah di masa depan ada tidak perlu menerapkan prinsip ini.

I.2.3 Interface Segregation Principle (ISP)

Motivasi

Ketika kita merancang sebuah aplikasi harus berhati-hati ketika membuat modul abstrak yang berisi beberapa submodul. Mengingat modul diimplementasikan oleh class, kita dapat memiliki sebuah abstraksi dari sistem dengan sebuah interface. Tetapi jika ingin memperluas aplikasi kita, menambahkan modul lain yang hanya berisi beberapa submodul dari sistem yang asli, kita dipaksa untuk mengimplementasikan interface secara penuh dan menulis beberapa metode kosong. Seperti sebuah interface yang dikenal interface lemak atau interface tercemar. Memiliki interface tercemar bukanlah solusi yang baik dan mungkin menyebabkan perilaku yang tidak tepat dalam sistem.

Interface Segregation Principle menyatakan bahwa Client tidak boleh dipaksa untuk mengimplementasikan interface yang tidak digunakan. Daripada sebuah interface gemuk lebih baik beberapa interface kecil yang terkelompokan berdasarkan metode, yang masing-masing melayani satu submodule.

Maksud

Client tidak boleh dipaksa untuk bergantung pada interface yang tidak digunakan.

Contoh

Di bawah ini adalah contoh yang melanggar Interface Segregation Principle. Kita memiliki class Manager yang mewakili orang yang mengelola para pekerja. Dan kita memiliki 2 jenis pekerja yaitu pekerja rata-rata dan beberapa pekerja yang sangat efisien. Keduanya bekerja dan butuh istirahat untuk makan. Tapi sekarang beberapa robot dipekerjakan juga di perusahaan, tetapi mereka tidak makan sehingga mereka tidak perlu istirahat. Di satu sisi class Robot baru perlu untuk mengimplementasikan

Page 11: Catatan Design Pattern by Ahmad Hidayat

interface IWorker karena robot bekerja. Di sisi lain, class Robot tidak perlu menerapkannya karena robot tidak makan.

Inilah sebabnya mengapa dalam kasus ini IWorker dianggap interface tercemar.

Jika kita menjaga desain ini, class Robot dipaksa untuk menerapkan metode makan. Kita bisa menulis sebuah class kosong yang tidak melakukan apa-apa (katakanlah istirahat makan 1 detik setiap hari), dan dapat mempunyai pengaruh yang tidak diinginkan dalam aplikasi (Misalnya manager akan melihat laporan makan siang yang diambil lebih dari jumlah orang yang ada).

Menurut Interface Segregation Principle, desain yang fleksibel tidak akan memiliki interface tercemar. Dalam kasus ini interface IWorker harus dibagi dalam 2 interface yang berbeda.

// interface segregation principle - bad exampleinterface IWorker {

public void work();public void eat();

}

class Worker implements IWorker{public void work() {

// ....working}public void eat() {

// ...... eating in launch break}

}

class SuperWorker implements IWorker{public void work() {

//.... working much more}

public void eat() {//.... eating in launch break

}}

class Manager {IWorker worker;

public void setWorker(IWorker w) {worker=w;

Page 12: Catatan Design Pattern by Ahmad Hidayat

}

public void manage() {worker.work();

}} Kode di bawah sudah mendukung Interface Segregation Principle. Dengan memisahkan interface IWorker dalam 2 interface yang berbeda, class Robot baru tidak lagi dipaksa untuk implement metode makan. Juga jika kita membutuhkan fungsi lain untuk robot seperti charging kita membuat interface lain yaitu IRechargeble dengan metode recharge.

// interface segregation principle - good exampleinterface IWorker extends Feedable, Workable {}

interface IWorkable {public void work();

}

interface IFeedable{public void eat();

}

class Worker implements IWorkable, IFeedable{public void work() {

// ....working}

public void eat() {//.... eating in launch break

}}

class Robot implements IWorkable{public void work() {

// ....working}

}

class SuperWorker implements IWorkable, IFeedable{public void work() {

//.... working much more}

public void eat() {//.... eating in launch break

}

Page 13: Catatan Design Pattern by Ahmad Hidayat

}

class Manager {Workable worker;

public void setWorker(Workable w) {worker=w;

}

public void manage() {worker.work();

}}

Kesimpulan

Jika desain seperti ini sudah dilakukan interface lemak dapat dipisahkan menggunakan Adapter pattern.

Seperti prinsip lainnya, Interface Segregation Principle adalah salah satu prinsip yang membutuhkan tambahan waktu dan usaha yang dihabiskan untuk menerapkannya selama waktu desain dan meningkatkan kompleksitas kode. Tapi itu menghasilkan desain yang fleksibel. Jika kita menerapkanya lebih daripada yang diperlukan, itu akan menghasilkan kode yang terdapat banyak interface dengan satu metode, sehingga penerapanya harus berdasarkan pengalaman dan akal sehat dalam mengidentifikasi daerah-daerah di mana perluasan kode lebih mungkin terjadi di masa depan.

I.2.4 Single Responsibility PrincipleMotivasi

Dalam konteks ini responsibility (tanggung jawab) dianggap sebagai salah satu alasan untuk berubah. Prinsip ini menyatakan bahwa jika kita memiliki 2 alasan untuk mengubah sebuah class, kita harus membagi fungsionalitasnya menjadi dua class. Setiap class hanya akan menangani satu tanggung jawab dan ketika kita perlu membuat satu perubahan kita akan membuatnyandalam class yang menanganinya. Ketika kita perlu membuat perubahan dalam class yang memiliki tanggung jawab yang lebih, perubahan dapat mempengaruhi fungsi lain dari class.

Single Responsibility Principle adalah prinsip sederhana dan intuitif, tetapi dalam prakteknya kadang-kadang sulit untuk bisa melakukannya dengan benar.

MaksudSebuah class harus memiliki satu alasan untuk berubah.

Page 14: Catatan Design Pattern by Ahmad Hidayat

Contoh

Mari kita asumsikan kita perlu obyek untuk melayani pesan email. Kita akan menggunakan interface IEmail dari contoh di bawah. Pada pandangan pertama semuanya terlihat baik-baik saja. Dengan melihat lebih dekat kita dapat melihat bahwa kami interface IEmail dan class Email memiliki 2 tanggung jawab (alasan untuk berubah). Yang pertama penggunaan class untuk melayani beberapa protokol email seperti pop3 atau imap. Jika protokol lain harus dapat didukung, obyek harus terserialisasi dengan cara lain dan kode harus ditambahkan untuk mendukung protokol baru. Yang kedua untuk mengelola field Konten. Bahkan jika konten adalah sebuah string mungkin kita ingin di masa depan untuk mendukung format HTML atau lainnya.

Jika kita tetap hanya satu class, setiap perubahan untuk sebuah tanggung jawab mungkin akan mempengaruhi yang lain: Menambahkan sebuah protokol baru akan menciptakan kebutuhan

untuk menambahkan kode untuk melakukan parsing dan serialisasi konten untuk setiap jenis field.

Menambahkan jenis konten baru (seperti html) membuat kita menambahkan kode untuk setiap protokol yang sudah diimplementasikan.

// single responsibility principle - bad exampleinterface IEmail {

public void setSender(String sender);public void setReceiver(String receiver);public void setContent(String content);

}

class Email implements IEmail {public void setSender(String sender) {// set sender; }public void setReceiver(String receiver) {// set receiver; }public void setContent(String content) {// set content; }

}

Kita bisa membuat interface baru dan class yang disebut IContent dan Content untuk membagi tanggung jawab. Setelah hanya satu tanggung jawab untuk masing-masing class memberi kita desain yang lebih fleksibel: menambahkan protokol baru menyebabkan perubahan hanya di class

Email. menambahkan jenis konten baru yang didukung menyebabkan

perubahan hanya di class Conten.

Page 15: Catatan Design Pattern by Ahmad Hidayat

// single responsibility principle - good exampleinterface IEmail {

public void setSender(String sender);public void setReceiver(String receiver);public void setContent(IContent content);

}

interface IContent {public String getAsString(); // used for serialization

}

class Email implements IEmail {public void setSender(String sender) {// set sender; }public void setReceiver(String receiver) {// set receiver; }public void setContent(IContent content) {// set content; }

}

Kesimpulan

Single Responsibility Principle merupakan cara yang baik untuk mengidentifikasi class selama fase desain sebuah aplikasi dan itu mengingatkan Anda untuk memikirkan semua cara class dapat berkembang. Sebuah pemisahan dari tanggung jawab yang baik ini dilakukan bila gambaran lengkap tentang bagaimana aplikasi harus bekerja dengan baik dimengerti.

I.2.5 Liskov's Substitution Principle(LSP)

MotivasiSepanjang waktu kita merancang modul program dan membuat beberapa hierarki class. Kemudian kita memperluas beberapa class, membuat beberapa classs turunan.

Kita harus memastikan bahwa class turunan baru hanya diperluas tanpa mengganti fungsi lama class. Kalau tidak, class-class baru dapat menghasilkan efek yang tidak diinginkan ketika mereka digunakan dalam modul program yang ada.

Likov's Substitution Principle ini menyatakan bahwa jika modul program menggunakan Base class, maka referensi ke Base class bisa diganti dengan class turunanya tanpa mempengaruhi fungsi dari modul program.

MaksudDerived types harus benar-benar disubstitusikan untuk base types nya.

Page 16: Catatan Design Pattern by Ahmad Hidayat

Contoh

Di bawah ini adalah contoh klasik yang melanggar Likov's Substitution Principle. Dalam contoh ini ada 2 class yang digunakan: Rectangle dan Square. Kita asumsikan bahwa objek Rectangle digunakan di suatu tempat di dalam aplikasi. Kita memperluas aplikasi dan menambahkan class Square. Class Square dikembalikan oleh factory pattern, didasarkan pada beberapa kondisi dan kita tidak tahu persis apa jenis objek yang akan dikembalikan. Tapi kita tahu itu Rectangle. Kita mendapatkan (get) objek rectangle, mengatur (set) lebar (width) sampai 5 dan tinggi (height) sampai 10 dan mendapatkan (get) area untuk rectangle dengan lebar (width) 5 dan tinggi (height) 10 luas area nya menjadi 50. Sebaliknya, hasilnya menjadi 100

// Violation of Likov's Substitution Principleclass Rectangle{

protected int m_width;protected int m_height;

public void setWidth(int width){m_width = width;

}

public void setHeight(int height){m_height = height;

}

public int getWidth(){return m_width;

}

public int getHeight(){return m_height;

}

public int getArea(){return m_width * m_height;

}}

class Square extends Rectangle {

public void setWidth(int width){m_width = width;m_height = width;

}

Page 17: Catatan Design Pattern by Ahmad Hidayat

public void setHeight(int height){m_width = height;m_height = height;

}

}

class LspTest{

private static Rectangle getNewRectangle(){

// it can be an object returned by some factory ... return new Square();

}

public static void main (String args[]){

Rectangle r = LspTest.getNewRectangle();

r.setWidth(5);r.setHeight(10);// user knows that r it's a rectangle. // It assumes that he's able to set the width and height as for the

base class

System.out.println(r.getArea());// now he's surprised to see that the area is 100 instead of 50.

}}

Kesimpulan

Prinsip ini hanyalah perpanjangan dari Open Close Principle dan itu berarti kita harus memastikan bahwa derived (turunan) class baru memperpanjang base class tanpa mengubah perilaku mereka.

II. Creational PatternsII.1 Singleton Pattern

Motivasi

Kadang-kadang penting untuk memiliki hanya satu instance untuk satu class. Misalnya, dalam suatu sistem harus ada hanya satu window manager (atau hanya satu sistem file atau hanya satu print spooler). Biasanya singletons digunakan untuk manajemen sumber daya internal atau eksternal terpusat dan menyediakan akses global untuk diri mereka sendiri.

Page 18: Catatan Design Pattern by Ahmad Hidayat

Singleton pattern merupakan salah satu design patterns paling sederhana: hanya melibatkan satu class yang responsible terhadap instance nya sendiri, untuk memastikan itu ciptakan tidak lebih dari satu instance, di saat yang sama memberikan sebuah akses global ke instance tersebut. Dalam kasus ini instance yang sama dapat digunakan dari mana-mana, karena tidak mungkin untuk memanggil konstruktor langsung setiap waktu.

Maksud

Memastikan bahwa hanya satu instance dari class yang dibuat. Memberikan global point untuk mengakses objek.

Implementasi

Implementasi melibatkan static member di dalam class "Singleton", sebuah private constructor dan sebuah static public method yang mengembalikan reference ke static member.

Singleton Pattern mendefinisikan operasi getInstance yang memperlihatkan instance unik yang diakses oleh Client. getInstance() bertanggung jawab untuk menciptakan instance class unik dalam kasus ini tidak dibuat dan untuk mengembalikan instance tersebut.

class Singleton{

private static Singleton instance;private Singleton(){

...}

public static synchronized Singleton getInstance()

Page 19: Catatan Design Pattern by Ahmad Hidayat

{if (instance == null)

instance = new Singleton();

return instance;}...public void doSomething(){

...}

}

Anda dapat melihat pada kode di atas bahwa metode getInstance memastikan hanya satu instance dari class yang dibuat. Konstruktor tidak boleh diakses dari luar class untuk memastikan satu-satunya cara instansiasi class hanya melalui metode getInstance.

Metode getInstance digunakan juga untuk memberikan akses dari luar ke objek dan dapat digunakan dengan cara berikut:

Singleton.getInstance().doSomething();

Contoh & Penerapan

Menurut definisi singleton pattern digunakan bila harus ada tepat satu instance dari class, dan ketika itu harus dapat diakses oleh Client dari titik akses global. Berikut adalah beberapa situasi nyata di mana singleton digunakan:

Contoh 1 - Logger Classes

Singleton pattern digunakan dalam desain class logger. Class ini umumnya diimplementasikan sebagai singleton, dan menyediakan global logging access point dalam semua komponen aplikasi tanpa perlu untuk menciptakan sebuah objek setiap kali operasi logging dilakukan.

Contoh 2 - Configuration Classes

Singleton pattern digunakan untuk merancang class yang menyediakan pengaturan konfigurasi untuk aplikasi. Dengan menerapkan configuration class sebagai Singleton tidak hanya menyediakan sebuah global access point, tapi kita juga tetap menggunakan instance sebagai cache dari objek. Ketika class sudah diinstansiasi (atau ketika nilai dibaca) singleton akan menjaga nilai-nilai dalam struktur internal. Jika nilai-nilai yang dibaca dari database atau dari file ini menghindari reload nilai setiap kali parameter konfigurasi digunakan.

Page 20: Catatan Design Pattern by Ahmad Hidayat

Contoh 3 - Accesing resources in shared mode

Hal ini dapat digunakan dalam desain sebuah aplikasi yang perlu untuk bekerja dengan port serial. Mari kita mengatakan bahwa ada banyak class dalam aplikasi, bekerja di lingkungan multi-threading, yang harus melakukan operasi pada port serial. Dalam kasus ini singleton dengan synchronized methods dapat digunakan untuk mengelola semua operasi pada port serial.

Contoh 4 - Factories implemented as Singletons

Mari kita asumsikan merancang aplikasi dengan sebuah factory untuk generate objek baru (Acount, Customer, Site, Address) dengan id mereka, dalam lingkungan multithreading. Jika factory telah diinstansiasi dua kali dalam 2 thread yang berbeda maka memungkinkan untuk memiliki 2 id tumpang tindih untuk 2 objek yang berbeda. Jika kita menerapkan Factory sebagai singleton kita menghindari masalah ini. Menggabungkan Abstract Factory atau Factory Method dan Singleton design patterns adalah praktek yang umum.

Implementasi dan Masalah Spesifik

Thread-safe diimplementasikan untuk penggunaan multi-threading.

Sebuah implementasi robust singleton harus dapat bekerja dalam kondisi apapun. Inilah sebabnya mengapa kita perlu memastikan untuk dapat bekerja ketika multiple threads menggunakannya. Seperti yang terlihat pada contoh sebelumnya singleton dapat digunakan khususnya dalam aplikasi multi-threaded untuk memastikan proses reads/writes tersinkronisasi.

Lazy instantiation menggunakan double locking mechanism.

Penerapan standar ditunjukkan dalam kode di atas adalah implementasi thread safe, tapi itu bukan penerapan terbaik thread-safe karena sinkronisasi sangat mahal ketika kita berbicara tentang kinerja. Kita bisa melihat bahwa metode getInstance sudah tersinkronisasi tidak perlu lagi diperiksa untuk sinkronisasi setelah objek diinisialisasi. Jika kita melihat bahwa objek singleton sudah dibuat kita hanya perlu mengembalikannya tanpa menggunakan syncronized block. Optimasi ini terdiri dari pemeriksaan di dalam sebuah unsynchronized block jika objek bernilai null dan jika tidak untuk diperiksa lagi dan menciptakannya dalam synchronized block. Ini disebut mekanisme penguncian ganda (double locking mechanism).

Page 21: Catatan Design Pattern by Ahmad Hidayat

Dalam kasus ini singleton instance dibuat ketika metode getInstance () dipanggil untuk pertama kalinya. Ini disebut lazy instantiation dan memastikan bahwa singleton instance dibuat hanya bila diperlukan.

//Lazy instantiation using double locking mechanism.class Singleton{

private static Singleton instance;

private Singleton(){System.out.println("Singleton(): Initializing Instance");}

public static Singleton getInstance(){

if (instance == null){

synchronized(Singleton.class){

if (instance == null){

System.out.println("getInstance(): First time getInstance was invoked!");

instance = new Singleton();}

} }

return instance;}

public void doSomething(){

System.out.println("doSomething(): Singleton does something!");}

}

Diskusi lebih detail (double locking mechanism) dapat ditemukan di http://www-128.ibm.com/developerworks/java/library/j-dcl.html?loc=j

Awal Instansiasi menggunakan implementasi dengan static field.

Dalam implementattion berikut obyek singleton diinstansiasi ketika class tersebut dimuat dan tidak ketika pertama kali digunakan, karena faktanya instance member dideklarasikan static. Inilah sebabnya mengapa kita tidak perlu untuk menyinkronkan setiap bagian dari kode dalam kasus ini. Class hanya dimuat sekali, ini menjamin uniquity dari objek.

Page 22: Catatan Design Pattern by Ahmad Hidayat
Page 23: Catatan Design Pattern by Ahmad Hidayat

Singleton - Contoh sederhana (java)

//Early instantiation using implementation with static field.class Singleton{

private static Singleton instance = new Singleton();

private Singleton(){

System.out.println("Singleton(): Initializing Instance");}

public static Singleton getInstance(){

return instance;}

public void doSomething(){

System.out.println("doSomething(): Singleton does something!");}

}

Protected constructor

Hal ini dimungkinkan untuk menggunakan protected constructor dalam rangka untuk memungkinkan subclassing dari singleton tersebut. Teknik ini memiliki 2 kelemahan yang membuat pewarisan singleton praktis: Pertama-tama, jika konstruktor adalah protected, itu berarti bahwa class dapat

instantiated dengan memanggil konstruktor dari class lain dalam paket yang sama. Sebuah solusi untuk menghindarinya adalah dengan membuat paket terpisah untuk singleton.

Kedua, untuk menggunakan class turunan semua panggilan getInstance harus diubah dalam kode yang ada dari Singleton.getInstance () untuk NewSingleton.getInstance ().

Multiple singleton instances jika class dimuat oleh classloaders yang berbeda mengakses sebuah singleton.

Jika sebuah class (nama yang sama, paket yang sama) yang dimuat oleh 2 classloaders yang berbeda, mereka mewakili 2 class yang berbeda di memori.

Serialization

Jika class Singleton mengimplementasikan interface java.io.Serializable, ketika singleton telah diserialisasi dan kemudian deserialized lebih dari sekali, ini akan ada multiple instances Singleton yang dibuat. Untuk menghindari hal ini metode

Page 24: Catatan Design Pattern by Ahmad Hidayat

readResolve harus diimplementasikan. Lihat Method Serializable() dan readResolve() dalam javadocs.

public class Singleton implements Serializable {...

// This method is called immediately after an object of this class is deserialized.

// This method returns the singleton instance.protected Object readResolve() {

return getInstance();}

}

Abstract Factory dan Factory Methods diimplementasikan sebagai singleton.

Ada situasi tertentu ketika sebuah factory harus unik. Memiliki 2 factory mungkin memiliki efek yang tidak diinginkan ketika objek diciptakan. Untuk memastikan factory yang unik, maka harus diimplementasikan sebagai singleton. Dengan demikian kita juga menghindari untuk instansiasi class sebelum menggunakannya.

Hot Spot:

Multithreading - Sebuah perawatan khusus harus diambil ketika singleton harus digunakan dalam aplikasi multithreading.

Serialization - Ketika singleton mengimplementasikan interface Serializable harus implementasikan metode readResolve untuk menghindari memiliki 2 objek yang berbeda.

Classloaders - Jika class Singleton diload oleh 2 class loader yang berbeda maka akan memiliki 2 class yang berbeda, satu untuk setiap class loader.

Global Access Point represented by the class name – Instance singleton diperoleh dengan menggunakan nama class. Pada pandangan pertama terlihat sebuah cara yang mudah untuk mengaksesnya, tetapi sangat tidak fleksibel. Jika kita perlu mengganti class Sigleton, semua references dalam kode harus diubah untuk menyesuaikan.

II.2 Factory Pattern

Motivasi

Factory Design Pattern mungkin adalah pattern desain yang paling banyak digunakan dalam bahasa pemrograman modern seperti Java dan C #. Muncul dalam berbagai varian dan implementasi. Jika Anda mencari tentang itu,

Page 25: Catatan Design Pattern by Ahmad Hidayat

kemungkinan besar, Anda akan menemukan referensi tentang GoF patterns: Factory Method dan Abstract Factory. Dalam artikel ini akan menggambarkan sebuah rasa dari factory pattern yang umum digunakan saat ini. Anda juga dapat mengecek original Factory Method yang sangat mirip.

Maksud

menciptakan objek tanpa memaparkan logika Instansiasi ke Client. mengacu pada objek yang baru dibuat melalui interface umum

Implementasi

Implementasi yang sangat sederhana Client membutuhkan Product, tapi bukannya menciptakan langsung

menggunakan operator new, ia meminta obyek factory untuk Product baru, memberikan informasi tentang jenis objek yang dibutuhkan.

Factory menginstansiasi sebuah new concrete product dan kemudian mengembalikan ke Client the newly created product (menolak abstract product class).

Client menggunakan Product sebagai Product abstrak tanpa mengetahui tentang implementasi konkret mereka.

Contoh & Penerapan

Mungkin factory pattern merupakan salah satu pattern yang paling sering digunakan.

Page 26: Catatan Design Pattern by Ahmad Hidayat

Misalnya aplikasi grafis bekerja dengan shapes. Dalam implementasi kita drawing framework adalah client dan shapes adalah product. Semua shapes berasal dari abstract shape class (atau interface). Class Shape mendefinisikan operasi draw dan move yang harus diimplentasikan oleh concrete shapes. Mari kita asumsikan perintah dipilih dari menu untuk membuat lingkaran baru. Framework tersebut menerima shape type sebagai parameter string, itu meminta factory untuk menciptakan shape baru mengirimkan parameter yang diterima dari menu. Factory menciptakan circle baru dan mengembalikannya ke framework, dilempar dengan bentuk abstrak. Kemudian framework menggunakan objek sebagai lemparan ke class abstrak tanpa menyadari jenis objek concret.

Keuntungannya jelas: bentuk baru dapat ditambahkan tanpa mengubah satu baris pun kode dalam framework (kode Client yang menggunakan bentuk dari factory). Seperti yang terlihat pada bagian selanjutnya, ada implementasi factory tertentu yang memungkinkan penambahan Product baru tanpa memodifikasi class factory.

Implementasi dan Masalah Spesifik

Procedural Solution - switch/case noob instantiation

Mereka juga dikenal sebagai parameterized Factories. Menghasilkan metode yang dapat ditulis sehingga dapat menghasilkan lebih banyak jenis obyek Product, menggunakan pengkondisian (dengan masukan sebagai parameter metode atau membaca dari beberapa parameter konfigurasi global - lihat pattern factory abstract pattern) untuk mengidentifikasi jenis objek yang harus dibuat , sebagai berikut:

public class ProductFactory{public Product createProduct(String ProductID){

if (id==ID1)return new OneProduct();

Page 27: Catatan Design Pattern by Ahmad Hidayat

if (id==ID2) returnreturn new AnotherProduct();

... // so on for the other Ids

return null; //if the id doesn't have any of the expected values } ...}

Implementasi ini adalah yang paling sederhana dan intuitif (Mari kita sebut saja noob implementation (implementasi pemula)). Disini masalahnya adalah sekali kita tambahkan concrete product call kita harus memodifikasi class factory. Hal ini sangat tidak fleksibel dan melanggar open close principle. Tentu saja kita bisa membuat subclass dari factory class, tetapi jangan lupa bahwa class factory biasanya digunakan sebagai singleton. Subclassing itu berarti mengganti semua referensi class factory di mana-mana melalui kode.

Class Registration - avoiding reflection

Jika Anda dapat menggunakan refleksi, misalnya di Java atau bahasa .NET, Anda dapat mendaftarkan class product baru ke factory tanpa mengubah factory itu sendiri. Untuk membuat objek di dalam class factory tanpa mengetahui jenis objek kita membuat sebuah pemetaan antara productID dan jenis class product. Dalam kasus ini ketika sebuah product baru ditambahkan ke aplikasi itu harus didaftarkan ke factory. Operasi ini tidak memerlukan perubahan kode class factory.

class ProductFactory{

private HashMap m_RegisteredProducts = new HashMap();

public void registerProduct (String productID, Class productClass){

m_RegisteredProducts.put(productID, productClass);}

public Product createProduct(String productID){

Class productClass = (Class)m_RegisteredProducts.get(productID);Constructor productConstructor = cClass.getDeclaredConstructor(new

Class[] { String.class });return (Product)productConstructor.newInstance(new Object[] { });

}}

Kita bisa menempatkan kode registrasi di manapun dalam kode kita, tapi tempat yang cocok adalah di dalam class product dalam konstruktor statis. Lihatlah contoh di bawah ini:

Page 28: Catatan Design Pattern by Ahmad Hidayat

1. Pendaftaran dilakukan di luar class Product:

public static void main(String args[]){Factory.instance().registerProduct("ID1", OneProduct.class);

}2. Pendaftaran dilakukan di dalam class Product:

class OneProduct extends Product{

static {Factory.instance().registerProduct("ID1",OneProduct.class);

}...

}

Kita harus memastikan bahwa concrete product classes sudah dimuat sebelum mereka diminta oleh factory untuk pendaftaran (jika mereka tidak dimuat mereka tidak akan didaftarkan di factory dan createProduct akan mengembalikan nilai null). Untuk memastikan itu kita akan menggunakan metode Class.forName tepat di bagian static dari main class. Bagian ini dijalankan tepat setelah main class di-load. Class.forName seharusnya mengembalikan instance class dari class yang ditunjukkan. Jika class tidak dimuat oleh kompilator sama sekali, itu akan dimuat saat Class.forName ini dipanggil. Akibatnya blok static di class masing-masing akan dieksekusi ketika masing-masing class dimuat:

class Main{

static{

try{

Class.forName("OneProduct");Class.forName("AnotherProduct");

}catch (ClassNotFoundException any){

any.printStackTrace();}

}public static void main(String args[]) throws

PhoneCallNotRegisteredException{

...}

}

Page 29: Catatan Design Pattern by Ahmad Hidayat

Implementasi refleksi memiliki kelemahan tersendiri. Yang utama adalah kinerja. Ketika refleksi digunakan kinerja pada kode yang melibatkan refleksi dapat menurunkan sampai 10% dari poerfomance dari kode non reflection. Masalah lainnya adalah bahwa tidak semua bahasa pemrograman menyediakan mekanisme refleksi.

Class Registration - avoiding reflection

Seperti kita lihat dalam paragraf sebelumnya obyek factory menggunakan internal HashMap untuk membuat pemetaan antara parameter (dalam kasus kita adalah Strings) dan concrete products class. Pendaftaran dibuat dari luar factory karena objek diciptakan menggunakan refleksi factory yang tidak mengetahui jenis objectnya.

Kita tidak ingin menggunakan refleksi tapi di saat yang sama kita ingin memiliki mengurangi coupling antara factory dan concrete products. Sejak factory harus tidak mengetahui product, kita harus memindahkan penciptaan object di luar factory untuk mengetahui object dari concrete product classes. Itu akan menjadi concrete class nya sendiri.

Kita menambahkan metode abstrak baru di class product abstrak. Setiap class concrete akan menerapkan metode ini untuk membuat objek baru dari jenis yang sama seperti dirinya sendiri. Kami juga harus mengubah metode registration tersebut bahwa kita akan meregistrasi obyek Product concrete bukan objek class.

abstract class Product{

public abstract Product createProduct();...

}

class OneProduct extends Product{

...static{

ProductFactory.instance().registerProduct("ID1", new OneProduct());

}public OneProduct createProduct(){

return new OneProduct();}...

}

Page 30: Catatan Design Pattern by Ahmad Hidayat

class ProductFactory{

public void registerProduct(String productID, Product p) {m_RegisteredProducts.put(productID, p);

}

public Product createProduct(String productID){

((Product)m_RegisteredProducts.get(productID)).createProduct();}

}

A more advanced solution - Factory design pattern with abstractions (Factory Method)

Implementasi ini merupakan alternatif untuk impelentasi class registration. Mari kita asumsikan kita perlu menambahkan Product baru ke aplikasi. Untuk implementasi switch-case prosedural kita perlu mengubah class Factory, sedangkan dalam implementasi class registration, kita butuh untuk mendaftarkan class untuk factory tanpa memodifikasi class factory sedikitpun. Untuk meyakinkan ini adalah solusi yang fleksibel.

Implementasi prosedural adalah contoh kasil yang buruk untuk Open-Close Principle. Seperti yang bisa kita lihat ada solusi yang paling intuitif untuk menghindari memodifikasi class Factory untuk memperluasnya.

Page 31: Catatan Design Pattern by Ahmad Hidayat

Ini adalah implementasi klasik dari factory method pattern. Ada beberapa kekurangan atas implementasi class registration dan tidak beigut banyak keuntungan:

+ derived factory method dapat diubah untuk melakukan operasi tambahan ketika objek diciptakan (mungkin beberapa inisialisasi berdasarkan beberapa parameter global ...).

- Factory tidak dapat digunakan sebagai singleton. - Setiap factory harus diinisialisasi sebelum menggunakannya. - Lebih sulit untuk diterapkan. - Jika objek baru harus ditambahkan sebuah factory baru harus diciptakan.

Pokoknya, implementasi klasik ini memiliki keuntungan bahwa itu akan membantu kita memahami Abstract Factory design pattern.

Kesimpulan

Bila Anda merancang aplikasi hanya berpikir jika Anda benar-benar membutuhkan sebuah factory untuk membuat objek. Mungkin menggunakannya akan membawa kompleksitas yang tidak perlu dalam aplikasi Anda. Jika Anda memiliki banyak object dari base type yang sama dan Anda memanipulasi mereka sebagian besar casted to abstract types, maka Anda perlu sebuah factory. Jika Anda harus memiliki banyak kode seperti berikut kode ini, Anda harus mempertimbangkan kembali itu:

(if (ConcreteProduct)genericProduct typeof )((ConcreteProduct)genericProduct).doSomeConcreteOperation();

Jika Anda memutuskan menggunakan factory, saya akan merekomendasikan menggunakan salah satu class registration implementations (dengan atau tanpa refleksi) dan untuk menghindari Metode Factory (Factory design pattern dengan abstractions). Harap dicatat implementasi switch-case prosedural (noob) adalah paling sederhana, melanggar prinsip OCP hanya digunakan untuk menjelaskan teori. Satu-satunya cara bijaksana untuk menggunakannya adalah untuk modul sementara sampai diganti dengan factory yang nyata.

II.3 Factory Method PatternMotivasi

Dikenal juga sebagai Virtual Constructor, Factory Method berkaitan dengan gagasan di mana libraries bekerja: library menggunakan abstract class untuk mendefinisikan dan memelihara relasi antara objek. Salah satu jenis responsibility nya adalah membuat object. Library diketahui ketika suatu objek perlu dibuat,

Page 32: Catatan Design Pattern by Ahmad Hidayat

tetapi tidak tahu jenis dari objek yang harus membuat, ini menjadi spesifik untuk aplikasi menggunakan library.

Factory method bekerja dengan cara yang sama: ia mendefinisikan sebuah interface untuk menciptakan objek, tetapi membuat pilihan dari tipenya pada subclass, penciptaan yang ditangguhkan pada saat run-time. Sebuah contoh kehidupan nyata sederhana Metode Factory adalah hotel. Ketika ingin tinggal di sebuah hotel pertama Anda harus check in. Orang yang bekerja di front-desk akan memberi Anda kunci untuk ruangan Anda setelah Anda membayar untuk ruangan yang Anda inginkan dan cara ini ia dapat dipandang sebagai sebuah ruang factory. Sementara tinggal di hotel, Anda mungkin perlu untuk melakukan panggilan telepon, sehingga Anda menelepon meja depan dan orang di sana akan menghubungkan Anda dengan nomor yang Anda butuhkan, menjadi sebuah “panggilan telepon” factory, karena ia mengontrol akses ke panggilan , juga.

Maksud

Mendefinisikan sebuah interface untuk menciptakan objek, tetapi membiarkan subclass untuk menentukan class untuk instansiasi

Mengacu pada objek yang baru dibuat melalui interface umum

Implementasi

Pattern dasarnya bekerja seperti yang ditunjukkan di bawah ini, dalam diagram UML:

Page 33: Catatan Design Pattern by Ahmad Hidayat

Class peserta dalam pattern ini adalah: Product mendefinisikan interface untuk objek yang dibuat metode factory. ConcreteProduct mengimplementasikan interface Product. Creator (juga disebut sebagai factory karena ia menciptakan obyek Product)

menyatakan metode FactoryMethod, yang mengembalikan objek Product. Mungkin memanggil generating metode untuk membuat objek Product

ConcreteCreator overrides the generating method untuk membuat objek ConcreteProduct

Semua concrete products adalah subclass dari class Product, sehingga semua dari mereka memiliki implementasi dasar yang sama, pada batas tertentu. Class Creator menentukan semua behavior standar dan generik dari Product dan ketika sebuah Product baru dibutuhkan, ia akan mengirimkan rincian penciptaan yang disediakan oleh Client untuk ConcreteCreator tersebut. Setelah diagram ini sudah di dalam pikiran, mudah bagi kita sekarang untuk menghasilkan kode yang berhubungan dengan itu. Berikut adalah bagaimana implementasi metode factory klasik akan terlihat:

public interface Product { � }

public abstract class Creator {

public void anOperation() {

Product product = factoryMethod();}

protected abstract Product factoryMethod();}

public class ConcreteProduct implements Product { � }

public class ConcreteCreator extends Creator {

protected Product factoryMethod() {

return new ConcreteProduct();}

}

public class Client {

public static void main( String arg[] ) {

Creator creator = new ConcreteCreator();creator.anOperation();

}

Page 34: Catatan Design Pattern by Ahmad Hidayat

}Contoh dan Penerapan

Kebutuhan untuk menerapkan Metode Factory sangat sering. Kasus nya seperti salah satunya di bawah ini: ketika class tidak dapat mengetahui lebih dulu tipe dari objek ingin dibuat ketika sebuah class ingin subclass untuk menjadi satu-satunya tipe spesifik dari

objek yang baru dibuat

Contoh 1 - Document Application.

Mempertimbangkan framework untuk aplikasi desktop. Aplikasi ini dimaksudkan untuk bekerja dengan document. Sebuah framework untuk aplikasi desktop terdapat definisi untuk operasi seperti opening, creating dan saving sebuah document. Class-class dasar yang abstrak, bernama Application dan Document, Client mereka harus membuat subclass dari mereka dalam rangka untuk menentukan aplikasi mereka sendiri. Untuk menghasilkan sebuah aplikasi menggambar, misalnya, mereka harus menentukan class DrawingApplication dan DrawingDocument. Class Aplication mempunyai tugas mengelola document, mengambil tindakan atas permintaan Client (misalnya, ketika pengguna memilih perintah open atau save dari menu).

Karena class Document perlu untuk diinstansiasi untuk aplikasi yang spesifik, class Application tidak tahu itu sebelumnya, sehingga tidak tahu apa yang harus diinstansiasi, tidak tahu kapan harus instantiate itu. Framework ini perlu instantiate class tertentu, tetapi hanya tahu class abstrak yang tidak dapat instantiated.

Factory Method design pattern memecahkan masalah dengan menempatkan semua informasi yang berkaitan dengan class yang perlu instantiated menjadi objek dan menggunakan mereka di luar framework, seperti yang Anda lihat di bawah ini

Page 35: Catatan Design Pattern by Ahmad Hidayat

Dalam class Application metode CreateDocument baik memiliki implementasi default atau tidak memiliki implementasi sama sekali, operasi ini sedang didefinisikan ulang dalam subclass MyApplication sehingga membuat objek MyDocument dan mengembalikan referensi untuk itu.

public Document CreateDocument(String type){if (type.isEqual("html"))

return new HtmlDocument();if (type.isEqual("proprietary"))

return new MyDocument();if (type.isEqual("pdf"))

return new PdfDocument ();}

Asumsikan class Application memiliki anggota disebut docs yang merupakan list dari document yang ditangani oleh aplikasi, maka metode NewDocument akan terlihat seperti ini:

public void NewDocument(String type){Document doc=CreateDocument(type);Docs.add(doc);Docs.Open();

}

Metode ini akan diwariskan oleh class MyApplication dan, sehingga, melalui metode CreateDocument, itu benar-benar akan instantiate objek MyDocument. Kita akan memanggil metode CreateDocument sebuah Method Factory karena bertanggung jawab dengan 'membuat' objek. Melalui metode ini, didefinisikan kembali dalam subclass Aplikasi, kita benar-benar dapat membentuk situasi di mana class Application menciptakan objek tanpa mengetahui jenis mereka. Dari sudut pandang ini metode factory adalah pattern yang memberikan kita cara untuk mencapai DIP principle.

Implementasi dan Spesifik Masalah

Ketika mengimplementasi Factory Method design pattern beberapa masalah yang dapat muncul:

Definisi dari Creator class

Jika kita menerapkan pattern ini ke kode yang sudah ditulis mungkin ada masalah dengan cara kita memiliki Creator class sudah ditetapkan. Ada dua kasus: class Creator adalah abstrak dan mengenerate metode yang tidak memiliki

implementasi apapun. Dalam hal ini class ConcreteCreator harus mendefinisikan metode generasi mereka sendiri dan situasi ini biasanya

Page 36: Catatan Design Pattern by Ahmad Hidayat

muncul dalam kasus-kasus di mana class Creator tidak dapat memprediksi apa yang akan diinstantiate ConcreteProduct.

Class Creator adalah class concrete, menghasilkan metode yang memiliki implementasi default. Jika ini terjadi, class ConcreteCreator akan menggunakan generating metode untuk fleksibilitas ketimbang untuk generasi. Programmer akan selalu dapat memodifikasi class objek yang class Creator implisit menciptakan, mendefinisikan ulang metode generasi.

Metode Factory hanya kasus tertentu dari factory design pattern. Pada saat yang sama itu adalah factory pattern yang paling dikenal, mungkin karena diterbitkan di GoF. Dalam bahasa pemrograman modern factory dengan registration lebih digunakan.

Kekurangan dan Manfaat

Berikut adalah manfaat dan kelemahan dari factory method pattern: + Alasan utama factory pattern yang digunakan adalah bahwa ia

memperkenalkan pemisahan antara aplikasi dan keluarga class (memperkenalkan kopling lemah bukan kopling ketat menyembunyikan class konkret dari aplikasi). Ini menyediakan cara sederhana untuk memperluas keluarga products dengan perubahan kecil dalam kode aplikasi.

+ Ini menyediakan kait kustomisasi. Jika objek yang dibuat secara langsung di dalam class sulit untuk menggantikan mereka dengan objek yang memperpanjang fungsi mereka. Daripada factory digunakan untuk menciptakan sebuah keluarga objek, customisasi objek dapat dengan mudah menggantikan objek aslinya, konfigurasikan factory untuk menciptakan mereka.

- Factory harus digunakan untuk keluarga object. Jika class tidak memperpanjang common base class atau interface mereka tidak dapat digunakan dalam template desain factory.

Hot Poin:

Metode factory adalah salah satu yang paling digunakan dan salah satu desain pattern yang lebih kuat. Hanya ada beberapa poin yang harus dipertimbangkan ketika Anda menerapkan metode factory.

Bila Anda merancang aplikasi hanya berpikir jika Anda benar-benar membutuhkannya sebuah factory untuk membuat objek. Mungkin menggunakannya akan membawa kompleksitas yang tidak perlu dalam aplikasi Anda. Namun demikian, jika Anda memiliki banyak objek dari tipe dasar yang sama dan Anda memanipulasi mereka kebanyakan sebagai obyek abstrak, maka Anda perlu sebuah factory. Code anda harus punya banyak kode seperti berikut, pertimbangkan ini.

Page 37: Catatan Design Pattern by Ahmad Hidayat

if (genericProduct typeof ConcreteProduct)((ConcreteProduct)genericProduct).doSomeConcreteOperation();

II.4 Abstract FactoryMotivasi

Modularisasi adalah isu besar dalam pemrograman saat ini. Programmer di seluruh dunia sedang mencoba untuk menghindari gagasan menambahkan kode ke class yang ada dalam rangka untuk membuat mereka mendukung encapsulasi informasi yang lebih umum. Ambil kasus seorang manajer informasi yang mengelola nomor telepon. Nomor telepon memiliki aturan tertentu di mana mereka bisa dihasilkan tergantung pada wilayah dan state. Jika di beberapa titik aplikasi harus diubah dalam rangka mendukung menambahkan angka membentuk state baru, kode aplikasi harus diubah dan itu akan menjadi lebih rumit.

Untuk mencegah hal itu, Abstract Factory design pattern digunakan. Menggunakan pattern ini, sebuah framework didefinisikan, yang menghasilkan objek-objek yang mengikuti pattern umum dan pada saat runtime factory ini dipasangkan dengan concrete factory untuk memProductsi objek-objek yang mengikuti pattern dari tempat tertentu. Dengan kata lain, Abstract Factory adalah super-factory yang menciptakan factories lain (factory of factories).

Maksud

Abstract Factory menawarkan interface untuk menciptakan sebuah keluarga obyek yang terkait, tanpa secara eksplisit menentukan class mereka.

Implementasi

Pattern basically bekerja seperti yang ditunjukkan di bawah ini, dalam diagram UML:

Page 38: Catatan Design Pattern by Ahmad Hidayat
Page 39: Catatan Design Pattern by Ahmad Hidayat

Class-class yang berpartisipasi Abstract Factory pattern di atas adalah:AbstractFactory - mendeklarasikan interface untuk operasi yang menciptakan abstract products.ConcreteFactory - mengimplementasikan operasi untuk menciptakan concrete products.AbstractProduct - mendeklarasikan sebuah interface untuk jenis objek product.Product - mendefinisikan Product yang akan dibuat oleh ConcreteFactory yang sesuai, menerapkan interface AbstractProduct.Client - menggunakan interface yang telah dideklarasikan oleh class AbstractFactory dan AbstractProduct.

Class AbstractFactory adalah salah satu yang menentukan jenis sebenarnya dari concrete object dan menciptakannya, tetapi mengembalikan sebuah abstract pointer ke concrete object yang baru saja dibuat. Ini menentukan perilaku client yang meminta factory untuk membuat sebuah objek dari tipe abstrak tertentu dan mengembalikan pointer abstrak untuk itu, menjaga client dari mengetahui apa-apa tentang penciptaan sebenarnya dari objek.

Fakta bahwa factory mengembalikan sebuah abstract pointer ke objek yang telah diciptakan, berarti bahwa client tidak memiliki pengetahuan tentang objek type nya. Ini berarti bahwa tidak ada kebutuhan untuk including deklarasi class apapun yang berkaitan dengan concrete type, client berurusan setiap saat dengan abstract type. Obyek dari concrete type yang dibuat oleh factory, diakses oleh client hanya melalui interface abstrak.

Implikasi kedua dari cara membuat objek adalah ketika menambahkan concrete type baru dibutuhkan, yang harus kita lakukan adalah memodifikasi kode client dan membuatnya menggunakan factory yang berbeda, yang jauh lebih mudah daripada instantiating type baru, yang mengharuskan mengubah kode di manapun objek baru dibuat.

Impelentasi klasik untuk Abstract Factory pattern adalah sebagai berikut:

abstract class AbstractProductA{public abstract void operationA1();public abstract void operationA2();

}

class ProductA1 extends AbstractProductA{ProductA1(String arg){

System.out.println("Hello "+arg);} // Implement the code herepublic void operationA1() { };public void operationA2() { };

}

Page 40: Catatan Design Pattern by Ahmad Hidayat

class ProductA2 extends AbstractProductA{ProductA2(String arg){

System.out.println("Hello "+arg);} // Implement the code herepublic void operationA1() { };public void operationA2() { };

}

abstract class AbstractProductB{//public abstract void operationB1();//public abstract void operationB2();

}

class ProductB1 extends AbstractProductB{ProductB1(String arg){

System.out.println("Hello "+arg);} // Implement the code here

}

class ProductB2 extends AbstractProductB{ProductB2(String arg){

System.out.println("Hello "+arg);} // Implement the code here

}

abstract class AbstractFactory{abstract AbstractProductA createProductA();abstract AbstractProductB createProductB();

}

class ConcreteFactory1 extends AbstractFactory{AbstractProductA createProductA(){

return new ProductA1("ProductA1");}AbstractProductB createProductB(){

return new ProductB1("ProductB1");}

}

class ConcreteFactory2 extends AbstractFactory{AbstractProductA createProductA(){

return new ProductA2("ProductA2");}AbstractProductB createProductB(){

return new ProductB2("ProductB2");}

}

//Factory creator - an indirect way of instantiating the factoriesclass FactoryMaker{

Page 41: Catatan Design Pattern by Ahmad Hidayat

private static AbstractFactory pf=null;static AbstractFactory getFactory(String choice){

if(choice.equals("a")){pf=new ConcreteFactory1();

}else if(choice.equals("b")){pf=new ConcreteFactory2();

} return pf;}

}

// Clientpublic class Client{

public static void main(String args[]){AbstractFactory pf=FactoryMaker.getFactory("a");AbstractProductA product=pf.createProductA();//more function calls on product

}}

Penerapan & Contoh

Kita harus menggunakan Abstract Factory design pattern ketika: sistem harus independen dari cara kerja product yang dibuat. sistem ini atau harus dikonfigurasi untuk bekerja dengan multiple families of

products. keluarga product dirancang hanya untuk bekerja bersama-sama. creation dari sebuah perpustakaan product dibutuhkan, yang relevan hanya

interface, bukan implementasi, juga.

Contoh Phone Number

Contoh pada awal artikel dapat ditambahkan dengan alamat, juga. Class AbstractFactory akan berisi metode untuk membuat entri baru dalam information manager untuk nomor telepon dan alamat, metode yang menghasilkan product abstract Alamat dan PhoneNumber, yang milik AbstractProduct class. Class-class AbstractProduct akan mendefinisikan metode product ini untuk mendukung: untuk alamat get dan set metode untuk jalan, kota, daerah dan anggota kode pos dan nomor telepon get dan set metode untuk nomor.

Class-class ConcreteFactory dan ConcreteProduct akan mengimplementasikan interface yang didefinisikan di atas dan akan muncul dalam contoh kita dalam bentuk class USAddressFactory dan class USAddress dan USPhoneNumber. Untuk setiap state baru yang perlu ditambahkan ke aplikasi, satu set baru class concrete-type akan ditambahkan. Dengan cara ini kita dapat memiliki EnglandAddressFactory, EnglandAddress dan EnglandPhoneNumber yang semuanya adalah file untuk informasi alamat Inggris.

Page 42: Catatan Design Pattern by Ahmad Hidayat

Contoh Pizza Factory

Contoh lain, kali ini lebih sederhana dan mudah dimengerti, adalah salah satu pizza factory, yang mendefinisikan nama metode dan return types untuk membuat berbagai jenis pizza. Abstrak factory dapat diberi nama AbstractPizzaFactory, RomeConcretePizzaFactory dan MilanConcretePizzaFactory menjadi dua ekstensi dari class abstrak. Abstrak factory akan menentukan jenis topping untuk pizza, seperti pepperoni, sosis atau ikan teri, dan beberapa concrete factory akan mengimplementasikan hanya satu set topping, dengan area yang spesifik dan bahkan jika salah satu topping diimplementasikan di kedua concrete factory, pizza yang dihasilkan akan subclass yang berbeda, masing-masing untuk area yang sudah diimplementasikan di dalamnya.

Contoh Look & Feel

Look & Feel Abstract Factory adalah contoh yang paling umum. Misalnya, framework GUI harus mendukung beberapa look and feel tema, seperti Motif dan Windows look. Gaya masing-masing mendefinisikan look dan behavior yang berbeda untuk setiap jenis control: Buttons dan Edit box. Untuk menghindari hardociding untuk setiap jenis kontrol kita mendefinisikan sebuah abstrak LookAndFeel. Panggilan ini akan instantiate, tergantung pada parameter konfigurasi dalam aplikasi dari concrete factories: WindowsLookAndFeel atau MotifLookAndFeel. Setiap permintaan untuk objek baru akan didelegasikan ke instatiated concrete factory yang akan mengembalikan control dengan jenis yang spesifik.

Page 43: Catatan Design Pattern by Ahmad Hidayat

Implementasi dan Masalah Spesifik

Abstract Factory pattern memiliki manfaat dan kekurangan. Di satu sisi, mengisolasi penciptaan objek-objek dari client yang membutuhkan mereka, client hanya diberi kemungkinan untuk mengakses mereka melalui interface, yang membuat manipulasi lebih mudah. Menukar keluarga product lebih mudah, sebagai concrete factory yang muncul hanya dalam kode dimana ia instantiated. Juga jika product dari keluarga dimaksudkan untuk bekerja sama, Abstract Factory memudahkan untuk menggunakan object-object hanya dari satu keluarga pada suatu waktu. Di sisi lain, menambahkan product baru ke factory yang sudah ada itu sulit, karena interface factory abstract menggunakan seperangkat product fix yang dapat dibuat. Itulah mengapa menambahkan Product baru berarti memperluas interface factory, yang melibatkan perubahan di class AbstractFactory dan semua subclass. Bagian ini akan membahas cara-cara menerapkan pattern untuk menghindari masalah yang mungkin muncul.

Factories sebagai singletons

Sebuah aplikasi biasanya membutuhkan hanya satu instance dari class ConcreteFactory per product keluarga. Ini berarti bahwa yang terbaik adalah menerapkannya sebagai Singleton.

Menciptakan Product

Class AbstractFactory hanya menyatakan interface untuk menciptakan Product. Ini adalah tugas dari class ConcreteProduct untuk benar-benar menciptakan Product. Untuk setiap keluarga, ide terbaik adalah menerapkan Factory Method design pattern. Sebuah concrete factory akan menentukan Productnya dengan masing-masing mengoverride metode factory. Bahkan jika implementasinya mungkin tampak sederhana, menggunakan ide ini berarti mendefinisikan subclass concrete factory baru untuk setiap product keluarga, bahkan jika class serupa dalam sebagian besar aspek.

Untuk menyederhanakan kode dan meningkatkan kinerja Prototype design pattern dapat digunakan sebagai pengganti Metode Factory, terutama ketika ada banyak keluarga Product. Dalam hal ini concrete factory diawali dengan prototypical instance dari setiap Product dalam keluarga dan ketika yang baru diperlukan bukannya menciptakan itu, Prototype yang ada di cloning. Pendekatan ini menghilangkan kebutuhan untuk concrete factory baru untuk setiap keluarga baru dari product.

Page 44: Catatan Design Pattern by Ahmad Hidayat

Memperluas factories

Pengoperasian perubahan factory dalam rangka untuk itu untuk mendukung terciptanya Product baru tidak mudah. Apa yang dapat dilakukan untuk mengatasi masalah ini adalah, bukan metode CreateProduct untuk setiap Product, menggunakan sebuah Create method tunggal yang mengambil parameter yang mengidentifikasi jenis Product yang dibutuhkan. Pendekatan ini lebih fleksibel, tapi kurang aman. Masalahnya adalah bahwa semua obyek yang dikembalikan oleh Create method akan memiliki interface yang sama, yaitu salah satu yang sesuai dengan jenis dikembalikan oleh Create method dan Client tidak akan selalu dapat mendeteksi dengan benar untuk class dengan instance yang benar-benar miliknya.

Hot Poin:Class AbstractFactory dideklarasikan hanya sebagai interface untuk menciptakan product. Penciptaan yang sebenarnya adalah tugas class ConcreteProduct, di mana pendekatan yang baik adalah menerapkan Factory Methode design pattern untuk setiap Product dari keluarga.Memperluas factories dapat dilakukan dengan menggunakan satu metode Create untuk semua Product dan melampirkan informasi tentang jenis Product yang dibutuhkan.

II.5 Builder Pattern

Motivasi

Aplikasi yang lebih kompleks adalah kompleksitas class dan objek yang digunakan meningkat. Objek yang kompleks terbuat dari bagian-bagian yang dihasilkan oleh objek-objek lain yang membutuhkan perawatan khusus ketika sedang dibangun. Sebuah aplikasi mungkin perlu sebuah mekanisme untuk membangun objek yang kompleks yang independen dari yang membentuk objeknya. Jika ini adalah masalah yang Anda sedang dihadapkan dengan, Anda mungkin ingin mencoba menggunakan Builder (atau Adaptive Builder) design pattern.

Pattern ini memungkinkan objek client untuk membangun sebuah obyek yang kompleks dengan hanya menetapkan jenis dan isi, yang terlindung dari rincian yang terkait dengan representasi objek. Dengan cara ini proses konstruksi dapat digunakan untuk membuat representasi yang berbeda. Logika proses ini adalah form terisolasi langkah-langkah yang sebenarnya digunakan dalam menciptakan obyek yang kompleks, sehingga proses dapat digunakan kembali untuk membuat form objek yang berbeda, set yang sama dari obyek sederhana seperti yang pertama.

Page 45: Catatan Design Pattern by Ahmad Hidayat

Maksud

Mendefinisikan instance untuk menciptakan objek tetapi membiarkan subclass memutuskan class mana yang di instantiate

Mengacu pada objek yang baru dibuat melalui interface umum

Implementasi

Builder design pattern menggunakan Factory Builder pattern untuk menentukan class concrete untuk memulai untuk membangun tipe objek yang diinginkan, seperti yang akan kita lihat di bawah dalam diagram UML:

Class yang berpartisipasi dalam pattern ini adalah: The Builder class menentukan sebuah interface abstrak untuk membuat

bagian-bagian dari obyek Product. The ConcreteBuilder membangun dan menempatkan bersama-sama bagian

dari Product dengan mengimplementasi interface Builder. Ini mendefinisikan dan melacak representasi itu menciptakan dan menyediakan sebuah interface untuk menyimpan product.

Direktur class mengkonstruksi obyek yang kompleks dengan menggunakan interface Builder.

The Product merupakan obyek yang kompleks yang sedang dibangun.

Client, yang mungkin berupa object lain atau client aktual yang memanggil main() metode aplikasi, inisiasi class Builder dan Director. Builder merupakan obyek yang kompleks yang perlu dibangun dalam object dan type yang lebih sederhana. Konstruktor di class Director menerima objek Builder sebagai parameter dari Client dan bertanggung jawab untuk memanggil metode yang sesuai dari class Builder. Dalam rangka menyediakan Client dengan interface untuk semua concrete Builders, class Builder harus menjadi salah satu abstrak. Dengan cara ini Anda dapat menambahkan jenis baru dari obyek yang kompleks dengan hanya

Page 46: Catatan Design Pattern by Ahmad Hidayat

mendefinisikan struktur dan menggunakan kembali logika untuk proses konstruksi yang sebenarnya. Client adalah satu-satunya yang perlu tahu tentang jenis baru, Director perlu mengetahui metode Builder yang dipanggil.

Contoh berikut ini membahas kasus aplikasi mengkonversi teks:

Client perlu mengkonversi document dari format RTF ke format ASCII. Untuk itu, dia akan memanggil createASCIIText metode yang mengambil sebagai parameter document yang akan dikonversi. Metode ini panggilan concrete builder, ASCIIConverter, yang meng-extends Builder, TextConverter, dan meng-override dua metode untuk mengubah karakter dan paragraf, dan juga Director, RTFReader, yang mem-parsing document dan memanggil metode builder tergantung pada tipe Token yang ditemui. Product, ASCIIText, dibangun langkah demi langkah, dengan menambahkan karakter yang dikonversi.

//Abstract Builderclass abstract class TextConverter{

abstract void convertCharacter(char c);abstract void convertParagraph();

}

// Productclass ASCIIText{

public void append(char c){ //Implement the code here }}

//Concrete Builderclass ASCIIConverter extends TextConverter{

ASCIIText asciiTextObj;//resulting product

/*converts a character to target representation and appends to the resulting*/object void convertCharacter(char c){

char asciiChar = new Character(c).charValue();//gets the ascii character

Page 47: Catatan Design Pattern by Ahmad Hidayat

asciiTextObj.append(asciiChar);}void convertParagraph(){}ASCIIText getResult(){

return asciiTextObj;}

}

//This class abstracts the document objectclass Document{

static int value;char token;public char getNextToken(){

//Get the next tokenreturn token;

}}

//Directorclass RTFReader{

private static final char EOF='0'; //Delimitor for End of Filefinal char CHAR='c';final char PARA='p';char t;TextConverter builder;RTFReader(TextConverter obj){

builder=obj;}void parseRTF(Document doc){

while ((t=doc.getNextToken())!= EOF){switch (t){

case CHAR: builder.convertCharacter(t);case PARA: builder.convertParagraph();

}}

}}

//Clientpublic class Client{

void createASCIIText(Document doc){ASCIIConverter asciiBuilder = new ASCIIConverter();RTFReader rtfReader = new RTFReader(asciiBuilder);rtfReader.parseRTF(doc);ASCIIText asciiText = asciiBuilder.getResult();

}public static void main(String args[]){

Client client=new Client();Document doc=new Document();client.createASCIIText(doc);

Page 48: Catatan Design Pattern by Ahmad Hidayat

system.out.println("This is an example of Builder Pattern");}

}

Contoh & Penerapan

Builder Pattern digunakan ketika: Membuat algoritma dari obyek yang kompleks yang independen dari bagian

yang benar-benar membentuk objek Sistem perlu untuk memungkinkan representasi yang berbeda untuk objek

yang sedang dibangun

Contoh 1 - Vehicle Manufacturer.

Mari kita ambil kasus vehicle manufacturer, dari satu set bagian, dapat membangun sebuah mobil, sepeda, sepeda motor atau skuter. Dalam hal ini Builder akan menjadi VehicleBuilder tersebut. VehicleBuilder menentukan interface untuk membangun salah satu kendaraan dalam daftar di atas, dengan menggunakan set dari bagian yang sama dan seperangkat rule yang berbeda untuk setiap jenis kendaraan. ConcreteBuilders akan menjadi builders yang attached pada setiap objects yang sedang dalam pembangunan. Product ini tentu saja vehicle yang sedang dibangun dan Direktur adalah manufacturer dan toko.

Contoh 1 - Students Exams.

Jika kita memiliki sebuah aplikasi yang dapat digunakan oleh para mahasiswa dari Universitas untuk menyediakan daftar nilai ujian mereka, aplikasi ini perlu dijalankan dengan cara yang berbeda tergantung pada pengguna yang menggunakannya, pengguna tersebut yang harus log in. Ini berarti bahwa misalnya, admin harus memiliki beberapa tombol diaktifkan, tombol yang perlu dinonaktifkan untuk mahasiswa, pengguna umum. Builder menyediakan interface untuk membangun form tergantung pada informasi login. Para ConcreteBuilders adalah bentuk spesifik untuk setiap jenis pengguna. Product ini adalah form akhir bahwa aplikasi akan digunakan dalam kasus tertentu dan Direktur adalah aplikasi yang, berdasarkan informasi login, membutuhkan form yang spesifik.

masalah Spesifik dan implementasi

Builder dan Abstrak Factory

Builder design pattern sangat mirip, pada batas tertentu, dengan Abstract Factory pattern. Itulah mengapa penting untuk dapat membuat perbedaan antara situasi ketika satu atau yang lain digunakan. Dalam kasus Abstract Factory, Client menggunakan metode factorys untuk membuat objek sendiri. Dalam kasus

Page 49: Catatan Design Pattern by Ahmad Hidayat

Builders, class Builder yang diinstruksikan tentang cara membuat objek dan kemudian diminta untuk membuatnya, tapi cara class disatukan terserah class Builder, detail ini membuat perbedaan antara two patterns.

Common interface for products

Dalam prakteknya Product yang diciptakan oleh concrete builders memiliki struktur yang berbeda, jadi jika tidak ada alasan untuk memperoleh Product yang berbeda dari sebuah class induk yang sama. Hal ini juga membedakan pattern Builder dari pattern Factory Abstrak yang menciptakan object-object yang berasal dari jenis umum.

II.6 Prototype PatternMotivasi

Pemrograman saat ini adalah semua tentang biaya. Saving merupakan masalah besar ketika datang untuk menggunakan sumber daya komputer, sehingga programmer melakukan yang terbaik untuk menemukan cara meningkatkan kinerja Ketika kita berbicara tentang pembuatan obyek kita dapat menemukan cara yang lebih baik untuk memiliki objek baru: cloning. Untuk ide ini satu pattern desain tertentu terkait: daripada penciptaan menggunakan clonning. Kita mengcloning objek, jika cost untuk menciptakan objek baru itu besar dan penciptaan adalah sumber daya yang intensif.

Prototype design pattern merupakan satu pertanyaan. Hal ini memungkinkan sebuah objek untuk membuat customized objects tanpa mengetahui class mereka atau rincian tentang bagaimana untuk menciptakan mereka. Sampai poin ini kedengarannya sangat mirip dengan Metode Factory pattern, perbedaannya the fact that for the Factory the palette of prototypical objects tidak pernah mengandung lebih dari satu objek.

Maksud

menentukan jenis objek yang dibuat menggunakan prototypical instance menciptakan objek baru dengan menyalin Prototype ini

Implementasi

Pattern ini menggunakan class abstrak, seperti yang kita lihat di bawah dan hanya ada tiga jenis class membuat implementasinya agak mudah.

Page 50: Catatan Design Pattern by Ahmad Hidayat

Class-class yang berpartisipasi dengan Prototype Pattern adalah: Client - menciptakan objek baru dengan meminta Prototype untuk

mengcloning dirinya sendiri. Prototype - menyatakan sebuah interface untuk cloning itu sendiri. ConcretePrototype - mengimplementasikan operasi untuk cloning itu sendiri.

Proses cloning dimulai ketika class diinisialisasi dan diinstantiated. Client meminta objek baru dari tipenya dan mengirimkan permintaan ke class Prototype. Sebuah ConcretePrototype, tergantung dari jenis objek yang diperlukan, akan menangani cloning melalui Clone() metode, membuat instance baru dari dirinya sendiri.

Berikut adalah contoh kode untuk Prototype Pattern:

public interface Prototype {public abstract Object clone ( );

}

public class ConcretePrototype implements Prototype {public Object clone() {

return super.clone();}

}

public class Client {

public static void main( String arg[] ) {

ConcretePrototype obj1= new ConcretePrototype ();ConcretePrototype obj2 = ConcretePrototype)obj1.clone();

}}

Page 51: Catatan Design Pattern by Ahmad Hidayat

Contoh ini agak sepele, tetapi penggunaan nyata dari pattern muncul saat kita tidak tahu apa yang kita sebenarnya cloning. Sebagai contoh jika kita membutuhkan objek yang baru dibuat untuk disimpan dalam hashtable kita dapat menggunakannya seperti ini:

// Violation of Likov's Substitution Principleclass Rectangle{

protected int m_width;protected int m_height;

public void setWidth(int width){m_width = width;

}

public void setHeight(int height){m_height = height;

}

public int getWidth(){return m_width;

}

public int getHeight(){return m_height;

}

public int getArea(){return m_width * m_height;

}}

class Square extends Rectangle {

public void setWidth(int width){m_width = width;m_height = width;

}

public void setHeight(int height){m_width = height;m_height = height;

}

Page 52: Catatan Design Pattern by Ahmad Hidayat

}

class LspTest{

private static Rectangle getNewRectangle(){

// it can be an object returned by some factory ... return new Square();

}

public static void main (String args[]){

Rectangle r = LspTest.getNewRectangle();

r.setWidth(5);r.setHeight(10);// user knows that r it's a rectangle.// It assumes that he's able to set the width and height as for the base

class

System.out.println(r.getArea());// now he's surprised to see that the area is 100 instead of 50.

}}

Penerapan & Contoh

Gunakan Prototype Pattern ketika sistem harus independen dari bagaimana Product itu created, composed, dan represented. dan: Class yang akan diinstansiasi ditentukan pada saat run-time Diperlukan untuk menghindari penciptaan hirarki factory Lebih mudah untuk menyalin instance yang ada daripada membuat yang baru.

Contoh 1

Dalam membangun stages untuk permainan yang menggunakan labirin dan object-object visual yang berbeda bertemu karakter diperlukan metode cepat menghasilkan haze map dengan menggunakan objek-objek yang sama: wall, door, passage, room... Prototype Pattern berguna dalam kasus ini karena bukan hard coding (menggunakan operasi baru) obyek kamar, pintu, dan objek dinding yang bisa instantiated, metode CreateMaze akan parameterized oleh berbagai objek kamar, pintu, dinding dan objek jalan, sehingga komposisi peta dapat dengan mudah diubah dengan mengganti objek prototipikal dengan yang berbeda.

Page 53: Catatan Design Pattern by Ahmad Hidayat

Client adalah metode CreateMaze dan class ConcretePrototype akan menjadi orang-orang membuat salinan untuk objek yang berbeda.

Contoh 2:

Misalkan kita melakukan analisis penjualan pada set data dari database. Biasanya, kita akan menyalin informasi dari database, merangkum itu menjadi obyek dan melakukan analisis. Tetapi jika analisis lain diperlukan pada set data yang sama, membaca database lagi dan menciptakan objek baru bukanlah ide yang terbaik. Jika kita menggunakan pattern Prototype maka obyek yang digunakan dalam analisis pertama akan dicloning dan digunakan untuk analisis lainnya.

Client di sini salah satu metode yang memproses obyek yang merangkum informasi dari database. Class-class ConcretePrototype yang akan menjadi class, dari objek yang sudah dibuat setelah penggalian data dari database, akan disalin ke obyek yang digunakan untuk analisis.

Spesifik masalah dan implementasi

Menggunakan prototype manager

Ketika aplikasi menggunakan banyak Prototype yang dapat diciptakan dan dihancurkan secara dinamis, registry Prototype yang tersedia harus dijaga. Registri ini disebut manajer Prototype dan harus melaksanakan operasi untuk mengelola Prototype terdaftar seperti mendaftarkan Prototype di bawah tombol tertentu, mencari Prototype dengan kunci yang diberikan, menghapus salah satu dari register, dll. Client akan menggunakan interface Prototype Manager untuk menangani Prototype pada saat run-time dan akan meminta izin sebelum menggunakan Clone() method.

Tidak ada banyak perbedaan antara pelaksanaan Prototype yang menggunakan manajer Prototype dan metode factory diimplementasikan menggunakan mekanisme registrasi class. Mungkin satu-satunya perbedaan terdapat dalam kinerja.

Melaksanakan operasi Clone

Sebuah diskusi kecil muncul ketika berbicara tentang seberapa dalam atau dangkal tiruan harus: a deep clone clones the instance variables in the cloning object while a shallow clone shares the instance variables between the clone and the original. Usually, a shallow clone is enough and very simple, but cloning complex prototypes should use deep clones so the clone and the original are independent, a

Page 54: Catatan Design Pattern by Ahmad Hidayat

deep clone needing its components to be the clones of the complex object’s components.

Initializing klon

Ada kasus ketika internal states dari clone harus diinisialisasi setelah dibuat. Hal ini terjadi karena nilai-nilai ini tidak dapat dikirimkan ke metode Clone(), yang menggunakan interface yang akan didestroy jika parameter tersebut digunakan. Dalam hal ini inisialisasi harus dilakukan dengan menggunakan pengaturan dan pengaturan ulang operasi dari class Prototype atau dengan menggunakan metode menginisialisasi yang mengambil sebagai parameter nilai-nilai di mana internal state clone itu harus diset.

Hot poin

Prototype Manager - diimplementasikan biasanya sebagai hashtable menjaga objek untuk mengcloning. Ketika menggunakannya, Prototype menjadi metode factory yang menggunakan cloning bukan Instansiasi.Deep Clones vs. Shallow Clones - ketika kita mengcloning objek kompleks yang berisi objek-objek lain, kita harus berhati-hati bagaimana mereka dicloning. Kita bisa mengcloning yang terkandung objek juga (deep cloning) atau kita dapat referensi yang sama bagi mereka, dan untuk berbagi antara cloned container objects.Initializing Internal States - ada situasi tertentu ketika object perlu diinisialisasi setelah mereka diciptakan.

II.7 Obyek Pool

Motivasi

Performa kadang dapat menjadi isu utama selama pengembangan perangkat lunak dan penciptaan objek (Instansiasi kelas) merupakan langkah mahal. Sementara Prototype pattern membantu dalam meningkatkan kinerja dengan kloning objek, Object Pool pattern menawarkan mekanisme untuk menggunakan kembali objek-objek yang mahal untuk dibuat.

Clients of an object pull "feel" like they are owners of a service although the service is shared among many other clients. Intent

-reuse and share objects that are expensive to create.

Page 55: Catatan Design Pattern by Ahmad Hidayat

Implementasi

Implementasinya melibatkan object-object berikut: Reusable - Wraps the limited resource, will be shared by several clients for a

limited amount of time. Client - uses an instance of type Reusable. ReusablePool - manage the reusable objects for use by Clients, creating and

managing a pool of objects.

Ketika Client meminta sebuah objek Reusable, pool melakukan tindakan berikut: Search for an available Reusable object and if it was found it will be returned

to the client. If no Reusable object was found then it tries to create a new one. If this actions

succeds the new Reusable object will be returned to the client. If the pool was unable to create a new Reusable, the pool will wait until a

reusable object will be re leased.

The Client is responsible to request the Reusable object as well to release it to the pool. If this action will not be performed the Reusable object will be lost, being considered unavailable by the ResourcePool.

The clients are not aware that they are sharing the Reusable object. From the client poinf of view they are the owners of a new object which comes from the Resource pool in the same way that it comes from a factory or another creational design pattern. The only difference is that the Client should mark the Reusable object as available, after it finishes to use it. It's not about releasing the objects; for example if we work with databases, when a connection is closed it's not necesarely distroyed, it means that it can be reused by another client.

Page 56: Catatan Design Pattern by Ahmad Hidayat

Mengapa menggunakannya?

Pada dasarnya, kita akan menggunakan object pool setiap kali ada beberapa Client yang membutuhkan the same stateless resource yang mahal untuk dibuat.

Penerapan & Contoh

Mari kita mengambil contoh koneksi database. Ini jelas yang membuka terlalu banyak koneksi dapat mempengaruhi kinerja karena beberapa alasan: Menciptakan connection adalah operasi yang mahal. Ketika ada terlalu banyak koneksi dibuka waktu lebih lama untuk membuat

yang baru dan server database akan menjadi kelebihan beban.

Here the object pool comes in to picture to manage the connections and provide a way to reuse and share them. It can also limit the maximum number of objects that can be created.

This pattern provide the following mechaninsm:

Connection - represent the object which is instantiated by the client. From the client perspective this object is instantiated and it handles the database operations and it is the only object visible to the client. The client is not aware that it uses some shared connections. Internally this class does not contain any code for connecting to the database and calls ConnectionPool.aquireImpl to get a ConnectionImpl object and then delegates the request to ConnectionImpl.

ConnectionImpl is the object which implements the database operations which are exposed by Connection for the client.

ConnectionPool is the main actor to manage the connections to the database. It keeps a list of ConnectionImpl objects and instantiates new objects if this is required.

Page 57: Catatan Design Pattern by Ahmad Hidayat

When the client needs to query the database it instantiate a new Connection object specifing the database name and the call the query method which returns a set of records. From the client point of view this is all.

When the Connection.Query methd is called it asks for a ConnectionImpl object from the ConnectionPool. The ConnectionPool tries to find and return an unused object and if it doesn't find it creates one. At this point the maximum number of connections can be limited and if it was reached the pool cand wait until one will be available or return null. In the query method the request is delegated to the ConnectionImpl object returned by the object pool. Since the request is just delegated it's recomended to have the same method signature in Connection and ConnectionImpl.

Specific problems and implementation

Singleton reusable pool - The reusable pool is implemented as a singleton. The reusable pool should be accesible only to the Connection object.

1. Limited number of resources in the pool

The connection pool is responsable for sharing and reusing the resources. Sometimes the resources have to be well managed only because they affects the performace, but there are situations when the number of resources can not exceed a specific limit. In this case the Resource pool check the number of instantiated resources and of the limit is reach it will wait for a resource to be released, it will throw an exception or it will return a null value. In any of the last 2 situations the Client should be notified that the action failed because there are no available resources.

2. Handling situations when creating a new resource fails

There are many reasons when the ResourcePool.acquireConnectionImpl method fails to return a resource. It might happens because there are not available resources or some exception occured. Either way the client should be notified about his.

3. Sinkronisasi

In order to work in a multithreading environment the methods that are used by differnt threads should be synchronized. There are only three methonds in the ResourcePool object that have to be synchronized:- getInstance should be synchronized or should contain a synchronized block.

For details check the singleton multithreading implementation.

Page 58: Catatan Design Pattern by Ahmad Hidayat

- acquireConnectionImpl - this menthod returns a resource and should be synchronized not to return the same resource to two different clients running tin different threads.

- releaseConnectionImpl - this method release a resource. Ussually it doesn't have to be synchronized a resource is allocated only by one client. Internally some blocks might need to be synchronized(depending on the method implementation and the internal structures used to keep the pool.).

4. Sumber daya Expired (tidak terpakai tapi masih milik)Masalah utama untuk Pola Pool Object adalah bahwa obyek harus dibebaskan oleh Client ketika selesai menggunakan mereka. Ada banyak contoh ketika Client "lupa" untuk melepaskan sumber daya. Mari kita ambil contoh yang koneksi database ketika koneksi tidak ditutup / dibebaskan setelah mereka digunakan. Hal ini tampaknya masalah kecil tetapi ada banyak aplikasi menghancurkan untuk alasan ini. Di pool objek dapat menerapkan mekanisme untuk memeriksa ketika sumber daya tertentu digunakan terakhir kali dan jika waktu berakhir, untuk mengembalikannya ke pool sumber daya yang tersedia.

Hot Poin

- Bila pola Pool Obyek digunakan obyek harus ditandai sebagai tersedia (dirilis) oleh Client setelah mereka digunakan, sehingga pool akan menyadari tentang hal ini. Ini adalah kelemahan utama karena Client harus melakukan ini dan itu adalah situasi umum ketika koneksi database tidak dirilis setelah mereka digunakan. Untuk mengatasi hal ini mekanisme dapat diimplementasikan untuk melepaskan sumber daya jika mereka tidak digunakan untuk jangka waktu.

- Menciptakan sumber daya akan gagal dan kasus ini harus ditangani dengan hati-hati. Ketika tidak ada sumber daya yang tersedia (beacause jumlah terbatas atau membuat yang baru gagal) Client harus diberitahu tentang hal itu.

KesimpulanAlthrough pool obyek menangani Instansiasi objek itu tujuan utama adalah untuk menyediakan cara untuk Client untuk menggunakan kembali objek seperti mereka adalah objek baru, tanpa dibagi dan digunakan kembali.

III. Behavioral Patterns3.1. Chain of Responsibility

Motivasi

Dalam menulis aplikasi apapun, sering terjadi bahwa event yang dihasilkan oleh satu objek harus ditangani oleh yang lain. And, to make our work even harder, we also happen to be denied access to the object which needs to handle the

Page 59: Catatan Design Pattern by Ahmad Hidayat

event. In this case there are two possibilities: there is the beginner/lazy approach of making everything public, creating reference to every object and continuing from there and then there is the expert approach of using the Chain of Responsibility.

Rantai pola Tanggung Jawab desain memungkinkan objek untuk mengirim perintah tanpa mengetahui apa yang objek akan menerima dan menanganinya. Permintaan dikirim dari satu objek ke yang lain membuat mereka bagian dari rantai dan setiap objek dalam rantai ini dapat menangani perintah, menyebarkannya atau melakukan keduanya. Contoh yang paling umum dari mesin menggunakan Rantai Tanggung jawab adalah slot mesin koin vending: daripada memiliki slot untuk setiap jenis koin, mesin hanya memiliki satu slot untuk mereka semua. Koin menjatuhkan diarahkan ke tempat penyimpanan yang sesuai yang ditentukan oleh penerima perintah.

Maksud: It avoids attaching the sender of a request to its receiver, giving this way

other objects the possibility of handling the request too. The objects become parts of a chain and the request is sent from one object to

another across the chain until one of the objects will handle it.

Diagram UML dari kelas bawah ini akan membantu kita lebih memahami cara Rantai bekerja.

Beberapa penjelasan tentang role dari setiap class dalam diagram di atas: Handler - defines an interface for handling requests RequestHandler - handles the requests it is responsible for if it can handle

the request it does so, otherwise it sends the request to its successor Client - sends commands to the first object in the chain that may handle the

command.

Page 60: Catatan Design Pattern by Ahmad Hidayat

Here is how sending a request works in the application using the Chain of Responsibility: the Client in need of a request to be handled sends it to the chain of handlers, which are classes that extend the Handler class. Each of the handlers in the chain takes its turn at trying to handle the request it receives from the client. If ConcreteHandler_i can handle it, then the request is handled, if not it is sent to the handler ConcreteHandler_i+1, the next one in the chain.

The classic example of the Chain of Responsibility's implementation is presented for us below:

public class Request {private int m_value;private String m_description;

public Request(String description, int value){

m_description = description;m_value = value;

}

public int getValue(){

return m_value;}

public String getDescription(){

return m_description;}

}

public abstract class Handler{

protected Handler m_successor;public void setSuccessor(Handler successor){

m_successor = successor;}

public abstract void handleRequest(Request request);}

public class ConcreteHandlerOne extends Handler{

Page 61: Catatan Design Pattern by Ahmad Hidayat

public void handleRequest(Request request){

if (request.getValue() < 0){ //if request is eligible handle it

System.out.println("Negative values are handled by ConcreteHandlerOne:");

System.out.println("\tConcreteHandlerOne.HandleRequest : " + request.getDescription()

+ request.getValue());}else{

super.handleRequest(request);}

} }

public class ConcreteHandlerThree extends Handler{

public void handleRequest(Request request){

if (request.getValue() >= 0){ //if request is eligible handle it

System.out.println("Zero values are handled by ConcreteHandlerThree:");

System.out.println("\tConcreteHandlerThree.HandleRequest : " + request.getDescription()

+ request.getValue());}

else{

super.handleRequest(request);}

}}

public class ConcreteHandlerTwo extends Handler{

public void handleRequest(Request request){

if (request.getValue() > 0){ //if request is eligible handle it

System.out.println("Positive values are handled by ConcreteHandlerTwo:");

Page 62: Catatan Design Pattern by Ahmad Hidayat

System.out.println("\tConcreteHandlerTwo.HandleRequest : " + request.getDescription()

+ request.getValue());}

else{

super.handleRequest(request);}

}}

public class Main {

public static void main(String[] args) {

// Setup Chain of ResponsibilityHandler h1 = new ConcreteHandlerOne();Handler h2 = new ConcreteHandlerTwo();Handler h3 = new ConcreteHandlerThree();h1.setSuccessor(h2);h2.setSuccessor(h3);

// Send requests to the chainh1.handleRequest(new Request("Negative Value ", -1));h1.handleRequest(new Request("Negative Value ", 0));h1.handleRequest(new Request("Negative Value ", 1));h1.handleRequest(new Request("Negative Value ", 2));h1.handleRequest(new Request("Negative Value ", -5));

}}

Penerapan & Contoh

Having so many design patterns to choose from when writing an application, it's hard to decide on which one to use, so here are a few situations when using the Chain of Responsibility is more effective: More than one object can handle a command The handler is not known in advance The handler should be determined automatically It’s wished that the request is addressed to a group of objects without

explicitly specifying its receiver The group of objects that may handle the command must be specified in a

dynamic wayHere are some real situations in which the Chain of Responsibility is used:

Page 63: Catatan Design Pattern by Ahmad Hidayat

Example 1

In designing the software for a system that approves the purchasing requests.

In this case, the values of purchase are divided into categories, each having its own approval authority. The approval authority for a given value could change at any time and the system should be flexible enough to handle the situation.

The Client in the example above is the system in need of the answer to the approval. It sends a request about it to an purchase approval authority. Depending on the value of the purchase, this authority may approve the request or forward it to the next authority in the chain.

For example let’s say a request is placed for the purchase of a new keyboard for an office. The value of the purchase is not that big, so the request is sent from the head of the office to the head of the department and then to the materials department where it stops, being handled locally. But if equipment for the whole department is needed then the request goes form the head of the department, to materials department, to the purchase office and even to the manager if the value is too big.

Example 2

In designing the software that uses a set of GUI classes where it is needed to propagate GUI events from one object to another.

When an event, such as the pressing of a key or the click of the mouse, the event is needed to be sent to the object that has generated it and also to the object or objects that will handle it.

The Client is, of course, the object that has generated the event, the request is the event and the handlers are the objects that can handle it. So, if we have a handler for the click of the mouse, a handler for the pressing of the ‘Enter’ key and a handler for the pressing of the ‘Delete’ key, that is the chain of handlers that take care of the events that are generated.

Example 3

In designing a shipping system for electronic orders.

The steps to complete and handle the order differs form one order to another based on the customer, the size of the order, the way of shipment, destination

Page 64: Catatan Design Pattern by Ahmad Hidayat

and more other reasons. The business logic changes also as special cases appear, needing the system to be able to handle all cases.

The Client, the electronic order in process, requests shipping based on a set of pieces of information. Its request is turned by the system into a specific form, combining the steps to completing and the details of handling, based on the input information. The system will send this type of request through a chain of order-handlers until the input information that it comes with matches the input the order-handles takes. When special cases appear, all that is needed is a new handler to be added in the chain.

Specific problems and implementation

The classic implementation of the Chain of Responsibility is just the first step in applying the pattern to our own application. Improvements based on the type of commands we are handling are needed, in order to make the use of this pattern effective.Representing requests

In real life each handler represents a system. And each system can handle specific requests or requests common to more handlers. We should take this issue in consideration when we implement this pattern. In the classical samples of the CoR found on the net you can see that the request is generally represented by an integer. Of course in real life we can not use primary data types as a request.

A clever design should be a flexible one. The best solution here is to create an interface a super class Request (or and interface) where to the default behavior. Then if we need to add a new handler and a specific request all we need is to extend the Request base class.

Of course this is not the only approach. Let’s consider the shipping system example. Each request will have to contain a large amount of data. Creating request examples for this might be difficult. We can take some xml objects containing the data, generated during the application flow (let’s assume we already have the code implemented for that) and pass them to each handler.

Or since the data was already saved in the database (let’s assume that also) we can pass only the id’s of the involved objects and then each handler will take the data required from db.

Unhandled requests

Page 65: Catatan Design Pattern by Ahmad Hidayat

Unfortunately, the Chain doesn't guarantee that every command is handled, which makes the problem worse, since unhandled commands propagate through the full length of the chain, slowing down the application. One way to solve this is by checking if, at the end of the chain, the request has been handled at least once, otherwise we will have to implement handlers for all the possible requests that may appear.

Broken Chain

Sometimes we could forget to include in the implementation of the handleRequest method the call to the successor, causing a break in the chain. The request isn’t sent forward from the broken link and so it ends up unhandled. A variation of the pattern can be made to send the request to all the handlers by removing the condition from the handler and always calling the successor.

The following implementation eliminates the Broken Chain problem. The implementation moves the code to traverse the chain into the base class keeping the request handling in a different method in the subclasses. The handleRequest method is declared as final in the base class and is responsible to traverse the chain. Each Handler have to implement the handleRequestImpl method, declared as abstract in the super class.

public abstract class Handler{private Handler m_successor;

public void setSuccessor(Handler successor){

m_successor = successor;}

protected abstract boolean handleRequestImpl(Request request);

public final void handleRequest(Request request){

boolean handledByThisNode = this.handleRequestImpl(request);if (m_successor != null && !handledByThisNode){

m_successor.handleRequest(request);}

} }

protected boolean handleRequestImpl(Request request){

Page 66: Catatan Design Pattern by Ahmad Hidayat

if (request.getValue() < 0){ //if request is eligible handle it

System.out.println("Negative values are handled by ConcreteHandlerOne:");

System.out.println("\tConcreteHandlerOne.HandleRequest : " + request.getDescription()

+ request.getValue());return true;

}else{

return false;}

}The above implementation not only that eliminates the broken chain problem, but it also offers an increased level of flexibility. Only by changing the handleRequest method we can change the pattern to send to al handlers regardless the request handling:

public final void handleRequest(Request request){

boolean handledByThisNode = this.handleRequestImpl(request);if (m_successor != null && !handledByThisNode)m_successor.handleRequest(request);

}Avoiding spam requests

For example, an improvement that we could find useful is avoiding sending spam commands. This way, the concrete extension of the HandleRequest function will look like this:

public void HandleRequest(int request) {

if(isSpam(request)) { // if the request is spam take spam-related actions

...}else { // request is not spam.

super.HandleRequest(request); // Pass message to next filter in the chain.

}}Use on existing code

Page 67: Catatan Design Pattern by Ahmad Hidayat

The last, but not least problem that the Chain of Responsibility creates to a programmer is the fact that it is impossible to introduce the pattern into the existing classes without modifying the source code and, even in the case where the pattern is already included in the code, if new operations need to be added to the Handler, it is impossible to do that without modifying the source code. So the basic idea is to decide from the start on whether to use the pattern or not and if we do, what methods we need.

Hot points

The fundamental flaw of the pattern is the fact that it gets easily broken: if the programmer forgets to call the next handler in the concreteHandler the request gets lost on the way. This problem comes from the fact that the execution is not handled entirely by the superclass and the call is triggered in the superclass.When implementing the CoR pattern a special care should be taken for the request representation. The request is not considered a distinctive part of the CoR pattern, but it is still used in all the components of the pattern.Another flaw of the Chain of Responsibility is the fact that some requests may end up unhandled due to the wrong implementation of concrete handler, their propagation slowing down the rest of the application. This means that extra care is needed when taking into account the requests that may appear in the process..

3.2. Command Pattern"Sebuah obyek yang berisi simbol, nama atau kunci yang mewakili daftar

command, tindakan atau penekanan tombol". Ini adalah definisi makro, salah

satu yang harus akrab/dikenal bagi setiap pengguna komputer. Dari ide ini pola

desain command tercipta/telah lahir.

Makro mewakili, pada batas tertentu, sebuah command yang dibangun dari

kumpulan seperangkat command lainnya, dalam urutan tertentu. Sama seperti

makro, pola desain Command merangkum/encapsulate command (metode

panggilan) pada objek yang memungkinkan kita untuk mengeluarkan permintaan

tanpa mengetahui operasi yang diminta atau meminta object. pola Command

desain menyediakan pilihan untuk command antrian (queue), undo / redo actions

dan manipulasi lainnya.

Maksudnya adalah:

- Merangkum permintaan dalam suatu objek.

Page 68: Catatan Design Pattern by Ahmad Hidayat

- memungkinkan parameterisasi klien dengan permintaan yang berbeda.

- memungkinkan menyimpan permintaan dalam sebuah antrian (queue).

Implementasi

Gagasan (ide) dan pelaksanaan (implementasi) pola desain Command cukup

sederhana, seperti yang akan kita lihat dalam diagram di bawah ini, hanya

membutuhkan sedikit class pelaksana (implementasi).

Clases yang berpartisipasi dalam pola desain command adalah:

Command : menyatakan sebuah interface untuk executing operasi;

Concrete Command : memperluas interface Command, menerapkan metode

Execute dengan menerapkan operasi yang sesuai pada Receiver. Ini

mendefinisikan hubungan antara Receiver dan action (tindakan).

Client (klien) : membuat objek ConcreteCommand dan menetapkan

penerima tersebut;

Invoker : meminta command untuk melaksanakan/membawa permintaan

tersebut;

Receiver : mengetahui bagaimana untuk melakukan operasi,

Klien meminta command yang akan dieksekusi. Invoker mengambil/membawa

command, merangkum dan menempatkannya dalam antrian (queue), dalam

kasus tersebut ada hal lain yang harus dilakukan pertama kali, dan

ConcreteCommand yang bertanggung jawab atas command yang diminta,

mengirim hasilnya ke Receiver.

Page 69: Catatan Design Pattern by Ahmad Hidayat

Berikut ini adalah pola kode sampel implementasi klasik menempatkan pesanan

untuk membeli dan menjual saham:

Klien menciptakan beberapa pesanan untuk membeli dan menjual saham

(ConcreteCommands). Kemudian pesanan akan dikirim ke agen (Invoker). Agen

mengambil pesanan dan menempatkan mereka ke sistem StockTrade (Receiver).

Agen menyimpan antrian internal dengan pesanan untuk ditempatkan. Mari kita

menganggap bahwa sistem StockTrade ditutup setiap hari Senin, namun agen

tetap menerima pesanan, dan antrian untuk diproses di kemudian hari.

public interface Order { public abstract void execute ( );}

// Receiver class.class StockTrade { public void buy() { System.out.println("You want to buy stocks"); } public void sell() { System.out.println("You want to sell stocks "); }}

// Invoker.class Agent { private m_ordersQueue = new ArrayList();

Page 70: Catatan Design Pattern by Ahmad Hidayat

public Agent() { } void placeOrder(Order order) { ordersQueue.addLast(order); order.execute(ordersQueue.getFirstAndRemove()); } }

//ConcreteCommand Class.class BuyStockOrder implements Order { private StockTrade stock; public BuyStockOrder ( StockTrade st) { stock = st; } public void execute( ) { stock . buy( ); }}

//ConcreteCommand Class.class SellStockOrder implements Order { private StockTrade stock; public SellStockOrder ( StockTrade st) { stock = st; } public void execute( ) { stock . sell( ); }}

// Clientpublic class Client { public static void main(String[] args) { StockTrade stock = new StockTrade(); BuyStockOrder bsc = new BuyStockOrder (stock); SellStockOrder ssc = new SellStockOrder (stock); Agent agent = new Agent();

agent.placeOrder(bsc); // Buy Shares agent.placeOrder(ssc); // Sell Shares }}

Penerapan & Contoh

Penerapan pola desain Command dapat ditemukan dalam kasus ini di bawah ini:

- objek parameterizes tergantung pada tindakan mereka harus dilakukan.

Page 71: Catatan Design Pattern by Ahmad Hidayat

- menentukan atau menambahkan dalam antrian dan mengeksekusi permintaan

pada waktu yang berbeda.

- menawarkan dukungan untuk tindakan undoable (metode Execute dapat

menghafal state dan memungkinkan akan kembali ke state tersebut).

- struktur sistem dalam operasi tingkat tinggi yang didasarkan pada operasi

primitif.

- objek decouples yang memanggil tindakan dari objek yang melakukan

tindakan. Penggunaan ini juga dikenal sebagai Produser – pola desain

konsumen.

Contoh dari pemesanan makan di restoran adalah salah satu yang sangat baik

ketika mencoba untuk penjelasan yang lebih baik tentang bagaimana pattern ini

bekerja:

Pelayan (Invoker) mencatat pesanan subscribers di bukunya. Perintah ini

kemudian diantrikan untuk pesanan yang akan dimasak dan akan dimasak

(Receiver) di mana pesanan (makanan) itu diproses.

Dalam hal ini pelaku dalam skenario adalah sebagai berikut: Client adalah

customer. Dia mengirimkan request kepada receiver (penerima) melalui waiter

(pelayan), yang mana adalah Invoker. Waiter merangkum (encapsulates)

command/perintah (order dalam kasus/hal ini) dengan menuliskan di cek dan

kemudian menempatkannya, menciptakan obyek ConcreteCommand yang

merupakan command itu sendiri. Receiver ini akan memasak pesanan tersebut,

Page 72: Catatan Design Pattern by Ahmad Hidayat

setelah menyelesaikan semua order yang dikirim kepadanya sebelum command

tersebut, mulai bekerja pada pesanan tersebut. Aspek lain yang terlihat dari

contoh adalah kenyataan bahwa pad untuk pesanan tidak hanya mendukung

pesanan dari menu, sehingga dapat mendukung command untuk memasak

banyak item (makanan) yang berbeda.

Dalam hal yang sama kita dapat mempertimbangkannya dari contoh sebuah toko

auto-repair. Orang-orang datang dengan mobil yang berbeda yang memiliki

masalah yang berbeda. Orang yang berada di meja depan mencatat informasi

(masalah) para customer dan menempatkan mobil pada antrian untuk diperbaiki.

Informasi (klaim) order yang dituliskan (encapsulated) dalam kertas yang akan

digunakan pemilik mobil ketika ia datang kembali untuk mengambil mobilnya

yang telah diperbaiki. Pada poin tertentu mobil akan menjadi item/hal pertama

dalam antrian dan mekanik akan memperbaikinya. Sama seperti pada contoh di

atas, Client adalah customer. Invoker adalah person yang berada di front desk

yang mencatat informasi tentang mobil dan permasalahannya,

ConcreteCommand adalah request (permintaan) untuk memperbaiki mobil dan

Receiver adalah mechanic.

Page 73: Catatan Design Pattern by Ahmad Hidayat

Implementasi yang paling banyak digunakan dari command pattern

adalah the one used to implement the undo options in applications:

Mari kita pertimbangkan calculator application. App lication ini merupakan

Client. Calculator (Receiver) kelas adalah kelas utama yang digunakan dalam

aplikasi untuk melakukan command/perintah. Mungkin juga sebagai kelas

dokumen jika kita memiliki aplikasi editor teks dan kita ngin menerapkan

operasi seperti copy / paste / etc .... Ketika aplikasi harus melakukan command,

itu menciptakan command dan mengirimkannya ke Invoker. Invoker memanggil

execute metode command dan menambahkannya ke daftar yang berisi semua

command/perintah. Metode execute dari command, mendelegasikan panggilan

ke objek Calculator. Ketika undo operation yang dilakukan, Invoker

menggunakan daftar dengan semua command yang pernah dijalankan dan

panggilan untuk masing-masing unexecuted method. Operasi Redo bekerja

dengan cara yang sama.

Page 74: Catatan Design Pattern by Ahmad Hidayat

Spesifik masalah dan implementasi

Sekarang kita telah memahami bagaimana pattern command bekerja, saatnya

untuk melihat kelebihan dan kekurangannya, juga.

Kecerdasan command/perintah

Ada dua ekstrem yang programmer harus dihindari saat menggunakan pattern

ini:

1. Command ini hanya hubungan antara receiver dan action yang melaksanakan

request

2. Command mengimplementasikan segala sesuatu sendiri, tanpa mengirim

apapun ke receiver (penerima).

Kita harus selalu ingat fakta bahwa receiver (penerima ) adalah orang yang tahu

bagaimana untuk melakukan operasi yang dibutuhkan, tujuan dari

command/perintah adalah untuk membantu client dalam mendelegasikan request

(permintaannya) secara cepat dan untuk memastikan command/perintah berakhir

di mana seharusnya.

Undo dan Redo tindakan

Sebagaimana disebutkan di atas, beberapa implementasi dari pola desain

Command termasuk bagian untuk mendukung dalam undo dan redo dari

tindakan. Dengan kata lain, dalam melakukan mekanisme untuk memperoleh

states lama dari objek Receiver itu sangat diperlukan, dengan kata lain untuk

mencapai hal ini ada dua pilihan:

- Sebelum menjalankan setiap command, snapshot dari state penerima

(receiver) disimpan dalam memori. Hal ini tidak memerlukan banyak upaya

pemrograman tapi tidak dapat selalu diterapkan. Misalnya melakukan hal ini

dalam aplikasi pengolahan gambar akan memerlukan gambar yang tersimpan

dalam memori setelah setiap langkah, yang secara praktis tidak mungkin.

- dalam menyimpan receiver objects states, himpunan operasi yang dilakukan

disimpan dalam memori. Dalam hal ini command dan receiver/penerima

classes harus menerapkan algoritma invers untuk membatalkan setiap

tindakan. Ini akan membutuhkan usaha pemrograman tambahan, tetapi

Page 75: Catatan Design Pattern by Ahmad Hidayat

sedikit memori yang akan diperlukan. Terkadang untuk tindakan undo / redo,

command harus menyimpan informasi lebih lanjut tentang state(state)

receiver objects. Ide yang bagus dalam kasus tersebut adalah dengan

menggunakan Memento Pattern.

Asynchronous Metode Invocation

Penggunaan lain untuk pola desain command adalah untuk menjalankan

command asynchronous di latar belakang sebuah aplikasi. Dalam hal ini Invoker

berjalan di thread utama dan mengirimkan permintaan ke receiver yang berada

(running) di thread yang terpisah. Invoker akan menyimpan antrian command

yang akan dijalankan dan akan mengirim antrian command ke receiver

sementara itu Asynchronous Metode Invocation menyelesaikan antrian

command tersebut.

Menggunakan satu thread yaitu di mana receiver berjalan/bekerja lebih dari

thread yang dapat diciptakan untuk ini. Tapi untuk masalah kinerja (pembuatan

thread adalah kebutuhan) jumlah thread harus dibatasi. Dalam hal ini Invoker

akan menggunakan kolam thread penerima(receiver) untuk menjalankan

command asynchronously.

Menambahkan command baru

Obyek command decouples adalah obyek yang memanggil(invokes) tindakan

dari objek yang melakukan tindakan. Ada implementasi dari pola di mana

Invoker instantiates adalah object command konkret. Dalam hal ini jika kita

perlu menambahkan jenis perintah baru kita perlu mengubah Invoker juga. Dan

ini akan melanggar Open Close Principle (OCP). Dengan kata lain, untuk

memiliki kemampuan menambahkan command baru dengan usaha minimum,

kita harus memastikan bahwa Invoker sadar hanya tentang command abstrak

class atau interface.

Page 76: Catatan Design Pattern by Ahmad Hidayat

Menggunakan perintah komposit

Ketika menambahkan command(perintah) baru dalam aplikasi, kita dapat

menggunakan pola komposit untuk grup command yang ada di command baru

lainnya. Dengan cara ini, macro dapat dibuat dari command yang ada.

Hot spot

The main advantage of the command design pattern is that it decouples the

object that invokes the operation from the one that know how to perform it. And

this advantage must be kept. There are implementations of this design pattern in

which the invoker is aware of the concrete commands classes. This is wrong

making the implementation more tightly coupled. The invoker should be aware

only about the abstract command class.

3.3. Mediator Pattern

Motivasi

Dalam rangka untuk memiliki desain berorientasi objek yang baik kita harus

membuat banyak kelas berinteraksi satu sama lain. Jika prinsip-prinsip tertentu

tidak diterapkan maka framework final akan berakhir dengan berantakan total di

mana setiap objek bergantung pada object-object lain dalam rangka untuk

dijalankan. Untuk menghindari tight coupled frameworks, kita perlu sebuah

mekanisme untuk memfasilitasi interaksi antara objek dalam cara bahwa object-

object yang tidak menyadari keberadaan object-object lainnya.

Mari kita ambil contoh dari layar. Ketika kita menciptakannya kita tambahkan

semua jenis kontrol ke layar. Kontrol ini perlu berinteraksi dengan semua kontrol

lainnya. Misalnya ketika tombol ditekan harus tahu apakah data tersebut valid

dalam kontrol lainnya. Seperti yang Anda lihat jika Anda membuat aplikasi yang

berbeda menggunakan form Anda tidak perlu memodifikasi setiap kelas kontrol

setiap kali Anda menambahkan kontrol baru ke form. Semua operasi antara

kontrol dikelola oleh bentuk kelas itu sendiri. Kelas ini disebut mediator.

Page 77: Catatan Design Pattern by Ahmad Hidayat

Maksud

Mendefinisikan objek yang mengenkapsulasi bagaimana satu set objek

berinteraksi. Mediator mempromosikan kopling longgar dengan menjaga object-

object dari mengacu satu sama lain secara eksplisit, dan itu memungkinkan Anda

merubah interaksi mereka secara mandiri.

Implementasi

Peserta

Kelas-kelas peserta dalam pola ini adalah:

Mediator

- mendefinisikan sebuah interface untuk berkomunikasi dengan Colleague

objects.

ConcreteMediator

- mengetahui colleague classes dan menyimpan referensi ke colleague objects.

- Mengimplementasikan komunikasi dan mentransfer pesan antara colleague

classes

colleague classes

- menyimpan referensi ke objek Mediator

- Berkomunikasi dengan Mediator kapan itu akan dikomunikasikan dengan

Colleague lain.

Page 78: Catatan Design Pattern by Ahmad Hidayat

Penerapan

Menurut Gamma et al, pola Mediator harus digunakan bila:

satu set objek berkomunikasi dengan cara yang didefinisikan dengan baik

tapi kompleks. Menghasilkan ketergantungan yang tidak terstruktur dan sulit

dipahami.

sulit menggunakan kembali obyek karena mengacu pada dan berkomunikasi

dengan banyak object lain.

perilaku yang didistribusikan antara beberapa kelas harus disesuaikan tanpa

banyak subclassing.

Contoh

Contoh 1 - Perpustakaan GUI

Contoh mediator adalah salah satu pola yang sudah digunakan dalam berbagai

aplikasi. Salah satu contoh yang diwakili oleh kelas Dialog dalam framework

aplikasi GUI. Sebuah Dialog window adalah kumpulan kontrol grafis dan non-

grafis. Kelas Dialog menyediakan mekanisme untuk memfasilitasi interaksi

antara kontrol. Sebagai contoh, ketika sebuah nilai baru dipilih dari objek

ComboBox Label memiliki untuk menampilkan nilai baru. Baik ComboBox dan

label tidak menyadari setiap struktur lainnya dan semua interaksi dikelola oleh

objek Dialog. Setiap kontrol tidak menyadari keberadaan kontrol lainnya.

Contoh 2 - Chat aplikasi

Aplikasi chat adalah contoh lain dari pola mediator. Dalam aplikasi chatting kita

dapat memiliki beberapa peserta. Ini bukan ide yang baik untuk menghubungkan

setiap peserta untuk semua yang lain karena jumlah koneksi akan sangat tinggi,

akan ada masalah teknis karena proxy dan firewall, dll .. . Solusi yang paling

tepat adalah memiliki hub di mana semua peserta akan terhubung, hub ini hanya

kelas mediator.

Page 79: Catatan Design Pattern by Ahmad Hidayat

Peserta:

Chatroom (Mediator) - Mendefinisikan interface untuk berinteraksi dengan

peserta

ChatroomImpl (ConcreteMediator) - mengimplementasikan operasi yang

didefinisikan oleh interface Chatroom. Operasi yang mengelola interaksi antara

object: ketika salah satu peserta mengirimkan pesan, pesan dikirim ke peserta

lainnya.

Peserta (collegue) - mendefinisikan sebuah interface bagi peserta.

HumanParticipant, Bot (ConcreteCollegue) - mengimplementasikan peserta,

peserta dapat menjadi manusia atau bot, masing-masing memiliki implementasi

yang berbeda tetapi menerapkan interface yang sama. Setiap peserta akan tetap

hanya sebuah referensi ke mediator.

Spesifik masalah dan implementasi

Abstrak Mediator

Tidak perlu untuk membuat kelas Mediator Abstrak atau interface asalkan

colleagues akan menggunakan hanya satu mediator. Definisi dari Mediator

abstrak diperlukan hanya jika colleagues perlu bekerja sama dengan mediator

yang berbeda.

Komunikasi antara mediator dan rekan

Ada berbagai cara untuk mewujudkan komunikasi antara colleagues dan

mediator nya:

Salah satu metode yang paling sering digunakan adalah dengan

menggunakan pola Observer. Mediator dapat juga meenjadi observer dan

Kolega yang dapat menerapkan observable(diamati) object. Setiap kali

perubahan yang dibuat dalam state objek observable (diamati), observer

(mediator) akan diberitahu dan memberitahu semua colleagues (rekan) object

lainnya.

Metode alternatif dapat digunakan untuk mengirim pesan ke mediator.

Misalnya sebuah delegasi sederhana dapat digunakan dan metode khusus

dapat terekspos oleh mediator

Page 80: Catatan Design Pattern by Ahmad Hidayat

Dalam implementasi lebih kompleks pesan asynchronous dapat ditambahkan

ke ke antrian pesan, dari mana mereka dapat dijemput oleh objek mediator

Kompleksitas objek Mediator

Obyek mediator menangani semua interaksi antara obyek peserta. Salah satu

potensi masalah adalah kompleksitas mediator ketika jumlah peserta tinggi dan

perbedaan kelas peserta yang tinggi. Jika Anda membuat dialog kustom untuk

aplikasi GUI Anda ingat bahwa setelah beberapa waktu dialog kelas menjadi

sangat kompleks karena mereka harus mengelola banyak operasi.

Konsekuensi

Seperti dengan pola desain yang lainnya, ada keuntungan dan kerugian dari

menggunakan Pola Mediator. Bagian berikut akan menguraikan secara singkat

beberapa isu-isu ini.

Keuntungan

Pemahaman - Mediator merangkum logika dari mediasi antara rekan-rekan.

Dari alasan ini 'lebih mudah untuk memahami logika ini karena disimpan

hanya dalam satu kelas.

Decoupled Colleagues - Kelas colleague yang benar-benar dipisahkan.

Menambahkan kelas colleague baru sangat mudah karena tingkat decoupling.

objek protokol Sederhana - Obyek colleague perlu berkomunikasi hanya

dengan object mediator. Praktis pola mediator mengurangi saluran

komunikasi yang dibutuhkan (protokol) dari banyak ke banyak ke satu ke

banyak dan banyak ke satu (many to many to one to many and many to one).

Batas Subclassing - Karena logika komunikasi seluruh dirumuskan oleh

kelas mediator, ketika logika ini perlu diperpanjang hanya kelas mediator

perlu diperpanjang.

Kekurangan

Kompleksitas - dalam prakteknya mediator cenderung menjadi lebih kompleks

dan rumit. Sebuah praktek yang baik adalah untuk berhati-hati untuk membuat

kelas mediator hanya bertanggung jawab untuk bagian komunikasi. Misalnya

saat mengimplementasikan layar yang berbeda kelas layar seharusnya tidak

Page 81: Catatan Design Pattern by Ahmad Hidayat

berisi kode yang bukan merupakan bagian dari operasi layar. Ini harus

dimasukkan ke dalam beberapa kelas lain.

Pattern yang Terkait

Ada beberapa pola desain yang sangat erat kaitannya dengan pola Mediator dan

sering digunakan dalam hubungannya dengan itu.

Facade Pattern - mediator disederhanakan menjadi pola facade jika mediator

adalah hanya kelas aktif dan colleagues adalah kelas pasif. Pola facade hanyalah

sebuah implementasi dari pola mediator yang mana mediator adalah satu-satunya

obyek yang memicu(triggering) dan menyerukan (invoking) tindakan di kelas

colleagues pasif. Facade ini menjadi panggilan oleh beberapa kelas eksternal.

Adapter Pattern - pattern mediator hanya "menengahi" permintaan antara kelas

colleague. Hal ini tidak seharusnya mengubah pesan yang diterima dan

dikirimnya, jika itu mengubah pesan tersebut maka itu adalah sebuah Adapter

pattern.

Observer Pattern - observer dan mediator adalah pola yang

sama/mirip/similiar, memecahkan masalah yang sama. Perbedaan utama antara

mereka adalah masalah alamat mereka. Observer pattern menangani komunikasi

antara observer dan subjek atau beberapa subjek. Ini sangat mungkin untuk

memiliki object-object yang dapat diamati baru ditambahkan. Di sisi lain dalam

pola mediator, kelas mediator adalah kelas paling mungkin

diwariskan(inherited).

Known Uses

Pada bagian berikut, kita akan membahas beberapa penggunaan pola Mediator di

dunia nyata. Anda akan menemukan Mediator dalam banyak situasi di mana

terdapat banyak komponen yang harus berinteraksi dengan satu sama lain dalam

cara yang kompleks.

User Interfaces

Mungkin pola mediator banyak digunakan dalam user interface. Hampir setiap

framework kerja GUI dibangun di sekitarnya. Seperti dibahas sebelumnya, kelas

yang mewakili forms (Dialog, Form, ...) merupakan mediator dan kontrol

masing-masing mewakili seorang rekan. Kelas form menyediakan mekanisme

Page 82: Catatan Design Pattern by Ahmad Hidayat

untuk memfasilitasi interaksi antara kontrol, sebuah inherited class dibuat setiap

kali layar baru dibuat dan kode yang spesifik ditulis di kelas ini. Dengan cara ini,

komunikasi kontrol dimediasi oleh kelas form ini. Java Message Service

The Java Message Service (JMS) API adalah Java Message Oriented

Middleware (MOM) API untuk mengirimkan pesan antara dua atau lebih klien.

JMS API mendukung 2 model. Salah satunya adalah model publikasi-

berlangganan (publish-subscribe). Ini merupakan implementasi dari pola

mediator. Pesan dapat dipublish berdasarkan topik tertentu. Penerbit harus

membuat langganan (subscription) untuk subscribers yang berbeda dapat

berlangganan. Nol atau lebih subscribers dapat berlangganan untuk menerima

pesan pada topik pesan tertentu. Penerbit dan subscribers tidak tahu satu sama

lain, subscribers dapat tidak aktive. Dalam hal ini subscribers menerima pesan

saat kembali aktif.

Kesimpulan

Mediator pattern digunakan untuk mengambil peran sebuah hub atau router dan

memfasilitasi komunikasi antara banyak kelas. Sebuah cara yang sama dapat

dibuat dengan sistem database. The mediator transform a hard to implement

relation of many to many, where each calls has to communicate with each other

class, in 2 relations, easy to implement, of many to one and one to many, where

the communication is handled by the mediator class.

3.4. Memento Pattern

Motivasi

Hal ini kadang-kadang diperlukan untuk menangkap state internal suatu obyek di

beberapa titik dan memiliki kemampuan untuk mengembalikan objek ke state

yang kemudian pada waktunya. Kasus seperti ini berguna jika terjadi kesalahan

atau kegagalan. Pertimbangkan kasus objek kalkulator dengan undo operation

seperti kalkulator hanya bisa mempertahankan daftar semua operasi sebelumnya

yang telah dilakukan dan dengan demikian akan mampu mengembalikan

perhitungan sebelumnya yang telah dilakukan. Hal ini akan menyebabkan objek

kalkulator untuk menjadi lebih besar, lebih kompleks, dan heavyweight, sebagai

objek kalkulator yang harus menyediakan tambahan fungsi undo dan harus

Page 83: Catatan Design Pattern by Ahmad Hidayat

menjaga daftar semua operasi sebelumnya. Fungsi ini bisa pindah dari kelas

kalkulator, sehingga menjadi sebuah eksternal (undo manager class) dapat

mengumpulkan state internal kalkulator dan menyimpannya. Namun

menyediakan akses eksplisit untuk setiap variabel state kalkulator untuk manajer

restore akan menjadi tidak praktis dan akan melanggar prinsip enkapsulasi.

MaksudTujuan dari pola ini adalah untuk menangkap state internal obyek tanpa

melanggar enkapsulasi dan dengan demikian memberikan rata-rata untuk

merestore objek ke state awal bila diperlukan.

Implementasi

Gambar di bawah menunjukkan diagram UML kelas untuk Pola Memento:

Memento

Menyimpan state internal objek Originator. State dapat mencakup sejumlah

variabel state.

The Memento harus memiliki dua interface, satu interface kepada CareTaker.

Interface ini tidak boleh mengizinkan operasi atau akses ke internal state

yang sudah disimpan oleh memento dan kemurnian enkapsulasi (thus honors

encapsulation). Interface lainnya adalah originator(pencetus/pemula) dan

memungkinkan originator(pencetus/pemula) untuk mengakses setiap variabel

state yang perlu untuk originator(pencetus/pemula) untuk mengembalikan

(restore) state (state) sebelumnya.

Originator

Membuat objek memento untuk menangkap originators internal state.

Gunakan obyek memento untuk mengembalikan state/ state sebelumnya.

Caretaker

Bertanggung jawab untuk menjaga memento.

Memento adalah buram/opaque kepada Caretaker, dan Caretaker tidak boleh

beroperasi di atasnya.

Page 84: Catatan Design Pattern by Ahmad Hidayat

Sebuah Caretaker ingin melakukan operasi pada Originator sementara memiliki

kemungkinan untuk rollback. Caretaker memanggil metode createMemento()

pada originator, meminta originator untuk menambahkan sebuah objek

memento. Pada titik ini originator menciptakan objek memento menyimpan state

(state) internal dan passing memento kepada carataker. Caretaker maintain obyek

memento dan melakukan operasi. Dalam hal kebutuhan untuk operasi undo,

Caretaker memanggil metode setMemento() pada originator dengan passing

maintained memento object. Originator akan menerima memento,

menggunakannya untuk merestore ke previous state.

Penerapan & Contoh

Pola memento digunakan ketika snapshot state obyek harus ditangkap sehingga

dapat dikembalikan ke state yang kemudian dan dalam situasi di mana secara

eksplisit parsing state objek akan melanggar enkapsulasi.

Contoh - Kalkulator sederhana dengan Undo Operasi.

contoh sederhana adalah kalkulator yang menemukan hasil penambahan dua

angka, dengan opsi tambahan untuk membatalkan operasi terakhir dan

mengembalikan hasil sebelumnya.

The code below shows the memento object interface to caretaker. Note that this

interface is a placeholder only and has no methods to honor encapsulation in that

the memento is opaque to the caretaker.

Page 85: Catatan Design Pattern by Ahmad Hidayat

package memento;

/**

* Memento interface to CalculatorOperator (Caretaker)

*/

public interface PreviousCalculationToCareTaker {

// no operations permitted for the caretaker

}

The code below shows the Memento to Originator interface; note that this

interface provides the necessary methods for the originator to restore its original

state.

package memento;

/**

* Memento Interface to Originator

*

* This interface allows the originator to restore its state

*/

public interface PreviousCalculationToOriginator {

public int getFirstNumber();

public int getSecondNumber();

}

The code below shows the memento implementation, note that the memento

must implement two interfaces, the one to the caretaker as well as the one to the

originator.

package memento;

/**

* Memento Object Implementation

*

* Note that this object implements both interfaces to Originator and CareTaker

Page 86: Catatan Design Pattern by Ahmad Hidayat

*/

public class PreviousCalculationImp implements

PreviousCalculationToCareTaker,

PreviousCalculationToOriginator {

private int firstNumber;

private int secondNumber;

public PreviousCalculationImp(int firstNumber, int secondNumber) {

this.firstNumber = firstNumber;

this.secondNumber = secondNumber;

}

@Override

public int getFirstNumber() {

return firstNumber;

}

@Override

public int getSecondNumber() {

return secondNumber;

}

}

The code below shows the calculator interface which is the originator interface

package memento;

/**

* Originator Interface

*/

public interface Calculator {

Page 87: Catatan Design Pattern by Ahmad Hidayat

// Create Memento

public PreviousCalculationToCareTaker backupLastCalculation();

// setMemento

public void restorePreviousCalculation(PreviousCalculationToCareTaker

memento);

// Actual Services Provided by the originator

public int getCalculationResult();

public void setFirstNumber(int firstNumber);

public void setSecondNumber(int secondNumber);

}

The code below shows the Calculator implementation which is the originator

implementation. Note that the backupLastCalculation method corresponds to

createMemento() method discussed previously, in this method the memento

object is created and all originator state is saved to the memento. Also note that

the method restorePreviousCalculation() method corresponds to setMemento()

method . Inside this method the logic to restore the previous state is executed.

package memento;

/**

* Originator Implementation

*/

public class CalculatorImp implements Calculator {

private int firstNumber;

private int secondNumber;

@Override

public PreviousCalculationToCareTaker backupLastCalculation() {

// create a memento object used for restoring two numbers

Page 88: Catatan Design Pattern by Ahmad Hidayat

return new PreviousCalculationImp(firstNumber,secondNumber);

}

@Override

public int getCalculationResult() {

// result is adding two numbers

return firstNumber + secondNumber;

}

@Override

public void restorePreviousCalculation(PreviousCalculationToCareTaker

memento) {

this.firstNumber =

((PreviousCalculationToOriginator)memento).getFirstNumber();

this.secondNumber =

((PreviousCalculationToOriginator)memento).getSecondNumber();

}

@Override

public void setFirstNumber(int firstNumber) {

this.firstNumber = firstNumber;

}

@Override

public void setSecondNumber(int secondNumber) {

this.secondNumber = secondNumber;

}

}

The code below shows the calculator driver which simulates a user using the

calculator to add numbers, the user calculates a result, then enters wrong

Page 89: Catatan Design Pattern by Ahmad Hidayat

numbers, he is not satisfied with the result and he hits Ctrl + Z to undo last

operation and restore previous result.

package memento;

/**

* CareTaker object

*/

public class CalculatorDriver {

public static void main(String[] args) {

// program starts

Calculator calculator = new CalculatorImp();

// assume user enters two numbers

calculator.setFirstNumber(10);

calculator.setSecondNumber(100);

// find result

System.out.println(calculator.getCalculationResult());

// Store result of this calculation in case of error

PreviousCalculationToCareTaker memento =

calculator.backupLastCalculation();

// user enters a number

calculator.setFirstNumber(17);

// user enters a wrong second number and calculates result

calculator.setSecondNumber(-290);

// calculate result

System.out.println(calculator.getCalculationResult());

Page 90: Catatan Design Pattern by Ahmad Hidayat

// user hits CTRL + Z to undo last operation and see last result

calculator.restorePreviousCalculation(memento);

// result restored

System.out.println(calculator.getCalculationResult());

}

}

Spesifik masalah dan implementasi

Basis Data Transaksi

operasi Transaksi pada database yang terjadi dalam atomic, consistent, durable,

and isolated fashion. Sebuah transaksi dapat berisi beberapa operasi pada

database, setiap operasi dapat berhasil atau gagal, namun transaksi menjamin

bahwa jika semua operasi berhasil, transaksi akan dilakukan (commit) dan akan

bersifat final. Dan jika operasi gagal, maka transaksi akan gagal dan semua

operasi akan dirollback dan meninggalkan database seolah-olah tidak ada yang

terjadi.

mekanisme rollback menggunakan pola desain memento. Pertimbangkan obyek

yang mewakili tabel database, manajer transaksi objek yang bertanggung jawab

melakukan transaksi harus melakukan operasi pada objek meja sementara

memiliki kemampuan untuk membatalkan operasi jika gagal, atau jika ada

operasi pada setiap objek meja lainnya gagal. Untuk dapat rollback, obyek

manajer transaksi akan meminta objek table untuk memento sebelum melakukan

operasi dan dengan demikian dalam kasus kegagalan, obyek memento akan

digunakan untuk mengembalikan tabel ke state sebelumnya.

Konsekuensi

Memento melindungi enkapsulasi dan menghindari mengekspos state internal

dan implementasi originator. Hal ini juga menyederhanakan kode originator

sehingga originator tidak perlu melacak state sebelumnya karena ini adalah

tanggung jawab CareTaker.

Page 91: Catatan Design Pattern by Ahmad Hidayat

Menggunakan pola memento dapat menjadi mahal tergantung pada jumlah

informasi state yang harus disimpan di dalam obyek memento. Selain itu

caretaker harus berisi logika tambahan untuk dapat mengelola memento.

Pattern Terkait

Pola Command - Command dapat menggunakan memento untuk

mempertahankan state untuk operasi undoable.

Known Uses

Undo dan restore operasi di sebagian besar perangkat lunak.

Transaksi database yang sudah dibahas sebelumnya.

3.5. Observer Pattern

Motivasi

Kita tidak bisa bicara tentang Pemrograman Berorientasi Obyek tanpa

mempertimbangkan state (state) objek. Semua pemrograman berorientasi objek

adalah tentang objek dan interaksinya. Kasus-kasus ketika objek-objek tertentu

perlu diberitahu tentang perubahan yang terjadi di objek lain itu sering terjadi.

Untuk memiliki desain yang baik berarti untuk memisahkan (decouple) sebanyak

mungkin dan untuk mengurangi dependensi. Pola Desain Observer dapat

digunakan setiap kali sebuah subjek harus diamati oleh satu atau lebih observer.

Mari kita asumsikan kita memiliki sebuah sistem saham yang menyediakan data

untuk beberapa jenis klien. Kami ingin punya klien diimplementasikan sebagai

aplikasi berbasis web tetapi dalam waktu dekat kita perlu menambahkan klien

untuk perangkat mobile, Palm atau Pocket PC, atau untuk memiliki sistem untuk

memberitahukan pengguna dengan peringatan sms. Sekarang mudah untuk

melihat apa yang kita butuhkan dari pola observer (observer): kita perlu untuk

memisahkan subjek (stock(saham) server) dari observer (observer) itu (aplikasi

client) sedemikian rupa bahwa menambahkan observer (observer) baru akan

menjadi transparan untuk server.

Maksud

Page 92: Catatan Design Pattern by Ahmad Hidayat

Mendefinisikan ketergantungan satu-ke-banyak antara obyek sehingga ketika

satu objek berubah state/stateya, semua dependen (yang tergantung/ tanggungan)

telah diberitahu dan diupdate secara otomatis.

Implementasi

Kelas-kelas peserta dalam pola ini adalah:

Observable - interface atau kelas abstrak mendefinisikan operasi untuk attaching

dan de-attaching oberserver kepada klien. Dalam buku GOF kelas / interface ini

dikenal sebagai Subyek.

ConcreteObservable - concrete Observable class. It maintain the state of the

object and when a change in the state occurs it notifies the attached Observers.

Observer - interface atau kelas abstrak mendefinisikan operasi yang akan

digunakan untuk memberitahu objek ini.

ConcreteObserverA, ConcreteObserver2 - concrete Observer

implementations.

Aliran ini sederhana: framework utama instantiate obyek ConcreteObservable.

Kemudian instantiate dan menempel concrete observers untuk menggunakan

Page 93: Catatan Design Pattern by Ahmad Hidayat

metode yang didefinisikan dalam Observable interface. Setiap kali perubahan

state subjek itu memberitahu semua observer yang terpasang dengan

menggunakan metode yang didefinisikan dalam interface Observer. Ketika

Observer baru ditambahkan ke aplikasi, semua yang perlu kita lakukan adalah

untuk instantiate dalam framework utama dan menambahkan melampirkannya

ke objek diamati. Kelas-kelas yang sudah dibuat akan tetap tidak berubah.

Penerapan & Contoh

Pola observer digunakan ketika:

- the change of a state in one object must be reflected in another object without

keeping the objects tight coupled.

- the framework we are writing needs to be enhanced in future with new

observers with minimal changes

Beberapa Contoh Klasik:

- Model View Controller Pattern - The observer pattern is used in the model

view controller (MVC) architectural pattern. In MVC the this pattern is used

to decouple the model from the view. View represents the Observer and the

model is the Observable object.

- Event management - This is one of the domains where the Observer patterns

is extensively used. Swing and .Net are extensively using the Observer

pattern for implementing the events mechanism.

Contoh - Kantor Berita

Mari kita 'mengambil contoh dari kantor berita. Sebuah kantor berita

mengumpulkan berita berita dan mempublikasikan mereka ke subscribers yang

berbeda. Kita perlu membuat framework kerja untuk dan agency untuk dapat

menginformasikan segera, ketika peristiwa terjadi, subscribersnya tentang acara

tersebut. Para subscribers dapat menerima berita dengan cara yang berbeda:

Email, SMS, ... Solusinya perlu luas cukup untuk mendukung jenis baru dari

subscribers (mungkin teknologi komunikasi baru akan muncul).

Page 94: Catatan Design Pattern by Ahmad Hidayat

Jelas, agency diwakili oleh kelas Observable(Subject) bernama NewsPublisher.

Yang satu ini dibuat sebagai kelas abstrak karena agency ingin membuat

beberapa jenis objek diamati: di awal hanya untuk berita bisnis, tapi setelah

beberapa waktu olahraga dan politik baru akan diterbitkan. Kelas concretenya

adalah BusinessNewsPublisher .

Logika observer diimplementasikan dalam NewsPublisher. Ini membuat list

semua subscribers dan menginformasikan mereka tentang berita terbaru. Para

subscribers yang diwakili oleh beberapa observer (SMSSubscriber,

EmailSubscriber). Kedua observer yang disebutkan di atas diwarisi dari

Subscribers tersebut. Subscribers adalah kelas abstrak yang dikenal untuk

penerbit. Penerbit tidak tahu tentang observer concrete, ia tahu hanya sekitar

abstraksi mereka.

Di kelas utama sebuah penerbit(observable) dibangun dan beberapa subscribers

(observer). Para subscribers yang berlangganan ke penerbit, mereka dapat

berhenti berlangganan. Dalam arsitektur ini, jenis baru dari subscribers dapat

dengan mudah ditambahkan (instant messaging, ...) dan jenis baru dari penerbit

(Berita Cuaca, Olahraga Berita, ...).

Page 95: Catatan Design Pattern by Ahmad Hidayat

Specific Implementation Problems

Banyak subyek Banyak observer

Ini bukan situasi umum tetapi ada kasus ketika ada banyak observer yang perlu

mengamati lebih dari satu subjek. Dalam hal ini observer perlu diberitahu tidak

hanya tentang perubahan, tetapi juga subjek yang merupakan subjek dengan state

berubah. Hal ini dapat diwujudkan sangat sederhana dengan menambahkan

referensi subjek dalam metode pemberitahuan pembaruan. Subjek akan melewati

sebuah referensi untuk dirinya sendiri (ini) untuk ketika memberitahu observer.

Siapa yang memicu update?

Komunikasi antara subjek dan observer yang dilakukan melalui metode notify

yang dideklarasikan dalam interface observer. Tapi siapa yang dapat dipicu baik

dari subjek atau objek observer. Biasanya metode notify dipicu oleh subjek

ketika state itu berubah. Tapi kadang-kadang ketika update itu sering, perubahan

berturut-turut dalam subjek akan menentukan banyak operasi refresh yang tidak

perlu di observer. Dalam rangka untuk membuat proses ini lebih efisien observer

dapat bertanggung jawab untuk memulai operasi notify ketika dianggap perlu.

Making sure Subject state is self-consistent before notification

State subjek harus konsisten ketika operasi notify dipicu. Jika perubahan yang

dibuat di state subjek setelah observer diberitahu, itu akan direfresh dengan state

tua. Hal ini tampaknya sulit untuk dicapai tetapi dalam praktek ini dapat dengan

mudah dilakukan ketika operasi subclass Subyek memanggil operasi yang

diwariskan. Dalam contoh berikut, observer diberitahu ketika subjek berada

dalam state tidak konsisten:

class Observable{

...

int state = 0;

int additionalState = 0;

public updateState(int increment)

Page 96: Catatan Design Pattern by Ahmad Hidayat

{

state = state + increment;

notifyObservers();

}

...

}

class ConcreteObservable extends Observable{

...

public updateState(int increment){

super.updateState(increment); // the observers are notified

additionalState = additionalState + increment; // the state is changed

after the notifiers are updated

}

...

}

Perangkap ini dapat dihindari dengan menggunakan metode template di

superclass subjek abstrak untuk memanggil operasi notify. Kemudian subclass

subjek akan mengimplementasi operasi (s) dari template tersebut:

class Observable{

...

int state = 0;

int additionalState = 0;

public void final updateState(int increment)

{

doUpdateState(increment);

notifyObservers();

}

public void doUpdateState(int increment)

{

state = state + increment;

Page 97: Catatan Design Pattern by Ahmad Hidayat

}

...

}

class ConcreteObservable extends Observable{

...

public doUpdateState(int increment){

super.doUpdateState(increment); // the observers are notified

additionalState = additionalState + increment; // the state is changed

after the notifiers are updated

}

...

}

Operasi yang didefinisikan di kelas dasar subjek yang memicu operasi notify

harus didokumentasikan.

Push dan pull metode komunikasi

Ada 2 metode dari passing data dari subjek ke observer ketika state sedang

berubah di sisi subjek:

Puss Model - Subyek mengirim informasi rinci tentang perubahan observer

apakah itu digunakan atau tidak. Karena subjek harus mengirim informasi

rinci observer ini mungkin tidak efisien ketika sejumlah besar data perlu

dikirim dan tidak digunakan. Aproach lain akan mengirim hanya informasi

yang diperlukan oleh observer. Dalam hal ini subjek harus dapat

membedakan antara berbagai jenis observer dan untuk mengetahui data yang

dibutuhkan dari masing-masing, yang berarti bahwa lapisan subjek lebih

digabungkan ke lapisan observer.

Pull Model - Subjek hanya memberitahukan observer ketika perubahan di

state itu muncul dan itu adalah tanggung jawab setiap observer untuk

menarik data yang dibutuhkan dari subjek. Hal ini bisa menjadi tidak efisien

karena komunikasi yang dilakukan dalam 2 langkah dan masalah yang

mungkin muncul dalam lingkungan multithreading.

Page 98: Catatan Design Pattern by Ahmad Hidayat

Specifying points of interests

Efisiensi dapat ditingkatkan dengan menetapkan yang merupakan peristiwa yang

setiap observer tertarik. Hal ini dapat diwujudkan dengan menambahkan kelas

baru mendefinisikan suatu aspek. When an observer is registering it will provide

the aspects in which it is interested:

class Subject{

...

void attach(Observer observer, Aspect interest);

...

}

Encapsulating complex update semantics

Ketika kita memiliki beberapa subjects dan observer, hubungan antara mereka

akan menjadi lebih kompleks. Pertama, yang memiliki hubungan many-to-many

lebih sulit untuk mengelola secara langsung. Kedua, hubungan antara subjek dan

observer dapat berisi beberapa logika. Mungkin kita ingin memiliki observer

yang diberitahu hanya ketika semua subjek akan mengubah state mereka. Dalam

hal ini kita harus memperkenalkan objek lain yang bertanggung jawab (disebut

ChangeManager) untuk actions berikut:

untuk memaintain hubungan many to many antara subyek dan observer

mereka.

untuk encapsulate logika untuk memberitahukan observer.

untuk menerima pemberitahuan dari subyek dan mendelegasikannya ke

observer (based on the logic it encapsulate)

Pada dasarnya Change Manager adalah observer karena jika akan diberitahu

tentang perubahan subjek dan dalam waktu yang sama adalah suatu subjek

karena memberitahu observer. The ChangeManager adalah implemenasi dari

pola Mediator.

Pola Observer biasanya digunakan dalam kombinasi dengan pola desain lainnya:

Page 99: Catatan Design Pattern by Ahmad Hidayat

Factory pattern - Ini sangat mungkin menggunakan factory pattern untuk

menciptakan observer sehingga tidak ada perubahan yang diperlukan bahkan

dalam framework utama. Observer baru dapat ditambahkan secara langsung

dalam file konfigurasi.

Template Method - Pola observer dapat digunakan bersama dengan Pola

Metode Template untuk memastikan bahwa state Subjek konsisten sebelum

pemberitahuan.

Mediator Pattern - Pola mediator dapat digunakan ketika kita memiliki

kasus-kasus kompleks yang mempunyai banyak subjek dan banyak observer.

3.6.

IV.