Saya sedang mempelajari Pola Dekorator seperti yang didokumentasikan di GOF .
Tolong, bantu saya memahami Pola Dekorator . Bisakah seseorang memberikan contoh kasus penggunaan di mana ini berguna di dunia nyata?
Saya sedang mempelajari Pola Dekorator seperti yang didokumentasikan di GOF .
Tolong, bantu saya memahami Pola Dekorator . Bisakah seseorang memberikan contoh kasus penggunaan di mana ini berguna di dunia nyata?
Jawaban:
Pola dekorator mencapai tujuan tunggal yaitu secara dinamis menambahkan tanggung jawab pada objek apa pun.
Pertimbangkan sebuah toko pizza. Di toko pizza mereka akan menjual beberapa varietas pizza dan mereka juga akan menyediakan topping di menu. Sekarang bayangkan situasi di mana jika toko pizza harus memberikan harga untuk setiap kombinasi pizza dan topping. Bahkan jika ada empat pizza dasar dan 8 topping berbeda, aplikasi akan menjadi gila mempertahankan semua kombinasi pizza dan topping konkret ini.
Di sinilah pola dekorator.
Sesuai pola dekorator, Anda akan menerapkan topping karena dekorator dan pizza akan didekorasi oleh dekorator topping itu. Praktis setiap pelanggan menginginkan topping dari keinginannya dan jumlah tagihan akhir akan terdiri dari pizza dasar dan topping tambahan yang dipesan. Setiap dekorator topping akan tahu tentang pizza yang sedang didekorasi dan harganya. Metode GetPrice () dari objek Topping akan mengembalikan harga kumulatif pizza dan topping.
Berikut adalah contoh kode penjelasan di atas.
public abstract class BasePizza
{
protected double myPrice;
public virtual double GetPrice()
{
return this.myPrice;
}
}
public abstract class ToppingsDecorator : BasePizza
{
protected BasePizza pizza;
public ToppingsDecorator(BasePizza pizzaToDecorate)
{
this.pizza = pizzaToDecorate;
}
public override double GetPrice()
{
return (this.pizza.GetPrice() + this.myPrice);
}
}
class Program
{
[STAThread]
static void Main()
{
//Client-code
Margherita pizza = new Margherita();
Console.WriteLine("Plain Margherita: " + pizza.GetPrice().ToString());
ExtraCheeseTopping moreCheese = new ExtraCheeseTopping(pizza);
ExtraCheeseTopping someMoreCheese = new ExtraCheeseTopping(moreCheese);
Console.WriteLine("Plain Margherita with double extra cheese: " + someMoreCheese.GetPrice().ToString());
MushroomTopping moreMushroom = new MushroomTopping(someMoreCheese);
Console.WriteLine("Plain Margherita with double extra cheese with mushroom: " + moreMushroom.GetPrice().ToString());
JalapenoTopping moreJalapeno = new JalapenoTopping(moreMushroom);
Console.WriteLine("Plain Margherita with double extra cheese with mushroom with Jalapeno: " + moreJalapeno.GetPrice().ToString());
Console.ReadLine();
}
}
public class Margherita : BasePizza
{
public Margherita()
{
this.myPrice = 6.99;
}
}
public class Gourmet : BasePizza
{
public Gourmet()
{
this.myPrice = 7.49;
}
}
public class ExtraCheeseTopping : ToppingsDecorator
{
public ExtraCheeseTopping(BasePizza pizzaToDecorate)
: base(pizzaToDecorate)
{
this.myPrice = 0.99;
}
}
public class MushroomTopping : ToppingsDecorator
{
public MushroomTopping(BasePizza pizzaToDecorate)
: base(pizzaToDecorate)
{
this.myPrice = 1.49;
}
}
public class JalapenoTopping : ToppingsDecorator
{
public JalapenoTopping(BasePizza pizzaToDecorate)
: base(pizzaToDecorate)
{
this.myPrice = 1.49;
}
}
Ini adalah contoh sederhana menambahkan perilaku baru ke objek yang ada secara dinamis, atau pola dekorator. Karena sifat bahasa dinamis seperti Javascript, pola ini menjadi bagian dari bahasa itu sendiri.
// Person object that we will be decorating with logging capability
var person = {
name: "Foo",
city: "Bar"
};
// Function that serves as a decorator and dynamically adds the log method to a given object
function MakeLoggable(object) {
object.log = function(property) {
console.log(this[property]);
}
}
// Person is given the dynamic responsibility here
MakeLoggable(person);
// Using the newly added functionality
person.log('name');
switch
atau sederhana if
, Anda akan dapat mengklaim bahwa ini adalah contoh yang bagus dari menambahkan perilaku secara dinamis ke kelas. TETAPI, kita membutuhkan setidaknya dua kelas untuk mendefinisikan dekorator dan benda-benda yang dihiasi dalam pola ini.
Perlu dicatat bahwa model Java i / o didasarkan pada pola dekorator. Layering pembaca ini di atas pembaca itu di atas ... adalah contoh dunia nyata dekorator.
Contoh - Skenario- Katakanlah Anda sedang menulis modul enkripsi. Enkripsi ini dapat mengenkripsi file yang jelas menggunakan DES - standar enkripsi data. Demikian pula, dalam suatu sistem Anda dapat memiliki enkripsi sebagai standar enkripsi AES - Advance. Anda juga dapat memiliki kombinasi enkripsi - DES Pertama, lalu AES. Atau Anda dapat memiliki AES pertama, lalu DES.
Diskusi- Bagaimana Anda akan memenuhi situasi ini? Anda tidak dapat terus membuat objek kombinasi tersebut - misalnya - AES dan DES - total 4 kombinasi. Dengan demikian, Anda perlu memiliki 4 objek individual. Ini akan menjadi kompleks karena jenis enkripsi akan meningkat.
Solusi - Terus susun kombinasi - tumpukan tergantung pada kebutuhan - pada saat run time. Keuntungan lain dari pendekatan tumpukan ini adalah Anda dapat melepasnya dengan mudah.
Inilah solusinya - dalam C ++.
Pertama, Anda memerlukan kelas dasar - unit dasar tumpukan. Anda dapat berpikir sebagai dasar tumpukan. Dalam contoh ini, file itu jelas. Mari kita ikuti selalu polimorfisme. Jadikan pertama sebagai kelas antarmuka dari unit dasar ini. Dengan cara ini, Anda bisa menerapkannya sesuai keinginan. Juga, Anda tidak perlu memikirkan ketergantungan sambil memasukkan unit mendasar ini.
Inilah kelas antarmuka -
class IclearData
{
public:
virtual std::string getData() = 0;
virtual ~IclearData() = 0;
};
IclearData::~IclearData()
{
std::cout<<"Destructor called of IclearData"<<std::endl;
}
Sekarang, terapkan kelas antarmuka ini -
class clearData:public IclearData
{
private:
std::string m_data;
clearData();
void setData(std::string data)
{
m_data = data;
}
public:
std::string getData()
{
return m_data;
}
clearData(std::string data)
{
setData(data);
}
~clearData()
{
std::cout<<"Destructor of clear Data Invoked"<<std::endl;
}
};
Sekarang, mari kita buat kelas abstrak dekorator - yang dapat diperluas untuk menciptakan segala jenis rasa - di sini rasanya adalah jenis enkripsi. Kelas abstrak dekorator ini terkait dengan kelas dasar. Dengan demikian, dekorator "adalah" semacam kelas antarmuka. Jadi, Anda perlu menggunakan warisan.
class encryptionDecorator: public IclearData
{
protected:
IclearData *p_mclearData;
encryptionDecorator()
{
std::cout<<"Encryption Decorator Abstract class called"<<std::endl;
}
public:
std::string getData()
{
return p_mclearData->getData();
}
encryptionDecorator(IclearData *clearData)
{
p_mclearData = clearData;
}
virtual std::string showDecryptedData() = 0;
virtual ~encryptionDecorator() = 0;
};
encryptionDecorator::~encryptionDecorator()
{
std::cout<<"Encryption Decorator Destructor called"<<std::endl;
}
Sekarang, mari kita buat kelas dekorator beton - Jenis enkripsi - AES -
const std::string aesEncrypt = "AES Encrypted ";
class aes: public encryptionDecorator
{
private:
std::string m_aesData;
aes();
public:
aes(IclearData *pClearData): m_aesData(aesEncrypt)
{
p_mclearData = pClearData;
m_aesData.append(p_mclearData->getData());
}
std::string getData()
{
return m_aesData;
}
std::string showDecryptedData(void)
{
m_aesData.erase(0,m_aesData.length());
return m_aesData;
}
};
Sekarang, katakanlah tipe dekoratornya adalah DES -
const std :: string desEncrypt = "DES Encrypted";
class des: public encryptionDecorator
{
private:
std::string m_desData;
des();
public:
des(IclearData *pClearData): m_desData(desEncrypt)
{
p_mclearData = pClearData;
m_desData.append(p_mclearData->getData());
}
std::string getData(void)
{
return m_desData;
}
std::string showDecryptedData(void)
{
m_desData.erase(0,desEncrypt.length());
return m_desData;
}
};
Mari kita membuat kode klien untuk menggunakan kelas dekorator ini -
int main()
{
IclearData *pData = new clearData("HELLO_CLEAR_DATA");
std::cout<<pData->getData()<<std::endl;
encryptionDecorator *pAesData = new aes(pData);
std::cout<<pAesData->getData()<<std::endl;
encryptionDecorator *pDesData = new des(pAesData);
std::cout<<pDesData->getData()<<std::endl;
/** unwind the decorator stack ***/
std::cout<<pDesData->showDecryptedData()<<std::endl;
delete pDesData;
delete pAesData;
delete pData;
return 0;
}
Anda akan melihat hasil berikut -
HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
DES Encrypted AES Encrypted HELLO_CLEAR_DATA
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Destructor called
Destructor called of IclearData
Encryption Decorator Destructor called
Destructor called of IclearData
Destructor of clear Data Invoked
Destructor called of IclearData
Di sini adalah diagram UML - Representasi kelas untuk itu. Dalam hal ini, Anda ingin melewatkan kode dan fokus pada aspek desain.
strategy pattern
?
Pola dekorator membantu Anda mengubah atau mengonfigurasi fungsionalitas objek Anda dengan merantai dengan subclass serupa lainnya dari objek ini.
Contoh terbaik adalah kelas InputStream dan OutputStream dalam paket java.io
File file=new File("target","test.txt");
FileOutputStream fos=new FileOutputStream(file);
BufferedOutputStream bos=new BufferedOutputStream(fos);
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.write(5);
oos.writeBoolean(true);
oos.writeBytes("decorator pattern was here.");
//... then close the streams of course.
Apa itu Pola Desain Penghias di Jawa.
Definisi formal dari pola Dekorator dari buku GoF (Pola Desain: Elemen Reusable Object-Oriented Software, 1995, Pearson Education, Inc. Penerbitan sebagai Pearson Addison Wesley) mengatakan Anda bisa,
"Lampirkan tanggung jawab tambahan pada objek secara dinamis. Dekorator memberikan alternatif yang fleksibel untuk subklasifikasi untuk memperluas fungsionalitas."
Katakanlah kita memiliki Pizza dan kita ingin menghiasinya dengan topping seperti Chicken Masala, Onion dan Mozzarella Cheese. Mari kita lihat bagaimana mengimplementasikannya di Java ...
Program untuk menunjukkan bagaimana menerapkan Pola Desain Dekorator di Jawa.
Pizza.java:
<!-- language-all: lang-html -->
package com.hubberspot.designpattern.structural.decorator;
public class Pizza {
public Pizza() {
}
public String description(){
return "Pizza";
}
}
package com.hubberspot.designpattern.structural.decorator;
public abstract class PizzaToppings extends Pizza {
public abstract String description();
}
package com.hubberspot.designpattern.structural.decorator;
public class ChickenMasala extends PizzaToppings {
private Pizza pizza;
public ChickenMasala(Pizza pizza) {
this.pizza = pizza;
}
@Override
public String description() {
return pizza.description() + " with chicken masala, ";
}
}
package com.hubberspot.designpattern.structural.decorator;
public class MozzarellaCheese extends PizzaToppings {
private Pizza pizza;
public MozzarellaCheese(Pizza pizza) {
this.pizza = pizza;
}
@Override
public String description() {
return pizza.description() + "and mozzarella cheese.";
}
}
package com.hubberspot.designpattern.structural.decorator;
public class Onion extends PizzaToppings {
private Pizza pizza;
public Onion(Pizza pizza) {
this.pizza = pizza;
}
@Override
public String description() {
return pizza.description() + "onions, ";
}
}
package com.hubberspot.designpattern.structural.decorator;
public class TestDecorator {
public static void main(String[] args) {
Pizza pizza = new Pizza();
pizza = new ChickenMasala(pizza);
pizza = new Onion(pizza);
pizza = new MozzarellaCheese(pizza);
System.out.println("You're getting " + pizza.description());
}
}
Saya telah menggunakan pola dekorator secara luas di tempat kerja saya. Saya membuat posting di blog saya tentang cara menggunakannya dengan logging.
Pola dekorator memungkinkan Anda menambahkan perilaku secara dinamis ke objek.
Mari kita ambil contoh di mana Anda perlu membangun aplikasi yang menghitung harga berbagai jenis burger. Anda perlu menangani variasi burger yang berbeda, seperti "besar" atau "dengan keju", yang masing-masing memiliki harga relatif terhadap burger dasar. Misalnya, tambahkan $ 10 untuk burger dengan keju, tambahkan ekstra $ 15 untuk burger besar, dll.
Dalam hal ini Anda mungkin tergoda untuk membuat subclass untuk menangani ini. Kami mungkin mengungkapkan ini di Ruby sebagai:
class Burger
def price
50
end
end
class BurgerWithCheese < Burger
def price
super + 15
end
end
Dalam contoh di atas, kelas BurgerWithCheese mewarisi dari Burger, dan mengganti metode harga untuk menambahkan $ 15 ke harga yang ditentukan dalam kelas super. Anda juga akan membuat kelas LargeBurger dan menentukan harga relatif terhadap Burger. Tetapi Anda juga perlu mendefinisikan kelas baru untuk kombinasi "besar" dan "dengan keju".
Sekarang apa yang terjadi jika kita perlu menyajikan "burger dengan kentang goreng"? Kami sudah memiliki 4 kelas untuk menangani kombinasi tersebut, dan kami perlu menambahkan 4 lagi untuk menangani semua kombinasi dari 3 properti - "besar", "dengan keju" dan "dengan kentang goreng". Kami membutuhkan 8 kelas sekarang. Tambahkan properti lain dan kita perlu 16. Ini akan tumbuh 2 ^ n.
Sebagai gantinya, mari kita coba mendefinisikan BurgerDecorator yang mengambil objek Burger:
class BurgerDecorator
def initialize(burger)
self.burger = burger
end
end
class BurgerWithCheese < BurgerDecorator
def price
self.burger.price + 15
end
end
burger = Burger.new
cheese_burger = BurgerWithCheese.new(burger)
cheese_burger.price # => 65
Dalam contoh di atas, kami telah membuat kelas BurgerDecorator, dari mana kelas BurgerWithCheese mewarisi. Kami juga dapat mewakili variasi "besar" dengan membuat kelas LargeBurger. Sekarang kita bisa mendefinisikan burger besar dengan keju saat runtime sebagai:
b = LargeBurger.new(cheese_burger)
b.price # => 50 + 15 + 20 = 85
Ingat bagaimana menggunakan pewarisan untuk menambahkan variasi "dengan kentang goreng" akan melibatkan penambahan 4 subkelas lainnya? Dengan dekorator, kami hanya akan membuat satu kelas baru, BurgerWithFries, untuk menangani variasi baru dan menangani ini saat runtime. Setiap properti baru akan membutuhkan lebih banyak dekorator untuk mencakup semua permutasi.
PS. Ini adalah versi singkat dari artikel yang saya tulis tentang penggunaan Pola Penghias di Ruby , yang dapat Anda baca jika Anda ingin mengetahui contoh yang lebih rinci.
Penghias:
Lihat artikel pembuatan sumber untuk lebih jelasnya.
Dekorator (Abstrak) : ini adalah kelas / antarmuka abstrak, yang mengimplementasikan antarmuka komponen. Ini berisi antarmuka Komponen. Dengan tidak adanya kelas ini, Anda memerlukan banyak subkelas ConcreteDecorators untuk kombinasi yang berbeda. Komposisi komponen mengurangi subkelas yang tidak perlu.
Contoh JDK:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
while(bis.available()>0)
{
char c = (char)bis.read();
System.out.println("Char: "+c);;
}
Lihat pertanyaan SE di bawah ini untuk diagram UML dan contoh kode.
Artikel yang berguna:
Contoh kata asli dari pola Penghias: VendingMachineDecorator telah dijelaskan @
Kapan Menggunakan Pola Penghias?
Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();
beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();
Dalam contoh di atas, Teh atau Kopi (Minuman) telah didekorasi dengan Gula dan Lemon.
Pola dekorator mencapai tujuan tunggal yaitu secara dinamis menambahkan tanggung jawab pada objek apa pun .
Model Java I / O didasarkan pada pola dekorator.
Ada contoh di Wikipedia tentang mendekorasi jendela dengan scrollbar:
http://en.wikipedia.org/wiki/Decorator_pattern
Berikut adalah contoh 'dunia nyata' dari "anggota tim, ketua tim dan manajer", yang menggambarkan bahwa pola dekorator tidak tergantikan dengan warisan sederhana:
https://zishanbilal.wordpress.com/2011/04/28/design-patterns-by-examples-decorator-pattern/
Beberapa waktu yang lalu saya telah refactored basis kode menggunakan pola dekorator, jadi saya akan mencoba menjelaskan kasus penggunaan.
Mari kita asumsikan kita memiliki seperangkat layanan dan berdasarkan apakah pengguna telah memperoleh lisensi layanan tertentu, kita perlu memulai layanan.
Semua layanan memiliki antarmuka yang sama
interface Service {
String serviceId();
void init() throws Exception;
void start() throws Exception;
void stop() throws Exception;
}
abstract class ServiceSupport implements Service {
public ServiceSupport(String serviceId, LicenseManager licenseManager) {
// assign instance variables
}
@Override
public void init() throws Exception {
if (!licenseManager.isLicenseValid(serviceId)) {
throw new Exception("License not valid for service");
}
// Service initialization logic
}
}
Jika Anda mengamati dengan seksama, ServiceSupport
tergantung pada LicenseManager
. Tetapi mengapa harus bergantung LicenseManager
? Bagaimana jika kami membutuhkan layanan latar belakang yang tidak perlu memeriksa informasi lisensi. Dalam situasi saat ini kita harus entah bagaimana berlatih LicenseManager
untuk kembali true
ke layanan latar belakang. Pendekatan ini tampaknya tidak baik bagi saya. Menurut saya cek lisensi dan logika lainnya saling orthogonal.
Jadi Pola Penghias datang untuk menyelamatkan dan di sini mulai refactoring dengan TDD.
class LicensedService implements Service {
private Service service;
public LicensedService(LicenseManager licenseManager, Service service) {
this.service = service;
}
@Override
public void init() {
if (!licenseManager.isLicenseValid(service.serviceId())) {
throw new Exception("License is invalid for service " + service.serviceId());
}
// Delegate init to decorated service
service.init();
}
// override other methods according to requirement
}
// Not concerned with licensing any more :)
abstract class ServiceSupport implements Service {
public ServiceSupport(String serviceId) {
// assign variables
}
@Override
public void init() {
// Service initialization logic
}
}
// The services which need license protection can be decorated with a Licensed service
Service aLicensedService = new LicensedService(new Service1("Service1"), licenseManager);
// Services which don't need license can be created without one and there is no need to pass license related information
Service aBackgroundService = new BackgroundService1("BG-1");
Mari kita ambil contoh PubG. Senapan serbu bekerja paling baik dengan zoom 4x dan sementara kita berada di atasnya, kita juga akan membutuhkan kompensator dan penekan. Ini akan mengurangi mundur dan mengurangi suara tembakan serta gema. Kami perlu menerapkan fitur ini di mana kami akan memungkinkan pemain untuk membeli senjata favorit mereka dan aksesori mereka. Pemain dapat membeli pistol atau aksesori atau semua aksesori dan mereka akan dibebankan sesuai.
Mari kita lihat bagaimana pola dekorator diterapkan di sini:
Misalkan seseorang ingin membeli SCAR-L dengan ketiga aksesori yang disebutkan di atas.
Ini akan mengarah ke diagram kelas seperti ini:
Sekarang, kita dapat memiliki kelas seperti ini:
public abstract class Gun {
private Double cost;
public Double getCost() {
return cost;
}
}
public abstract class GunAccessories extends Gun { }
public class Scarl extends Gun {
public Scarl() {
cost = 100;
}
}
public class Suppressor extends GunAccessories {
Gun gun;
public Suppressor(Gun gun) {
cost = 5;
this.gun = gun;
}
public double getCost(){
return cost + gun.getCost();
}
}
public class GunShop{
public static void main(String args[]){
Gun scarl = new Scarl();
scarl = new Supressor(scarl);
System.out.println("Price is "+scarl.getCost());
}
}
Kami juga dapat menambahkan aksesori lain dan menghias Pistol kami.
Referensi:
https://nulpointerexception.com/2019/05/05/a-beginner-guide-to-decorator-pattern/
Pola Desain Penghias : Pola ini membantu memodifikasi karakteristik suatu objek saat runtime. Ini memberikan rasa yang berbeda untuk suatu objek dan memberikan fleksibilitas untuk memilih bahan apa yang ingin kita gunakan dalam rasa itu.
Contoh Kehidupan Nyata: Katakanlah Anda memiliki kursi kabin utama dalam penerbangan. Sekarang Anda diperbolehkan memilih beberapa fasilitas dengan tempat duduk. Setiap kemudahan memiliki biaya sendiri yang terkait dengannya. Sekarang jika pengguna memilih Wifi dan makanan premium, ia akan dikenakan biaya untuk kursi + wifi + makanan premium.
Dalam hal ini pola desain dekorator dapat sangat membantu kami. Kunjungi tautan di atas untuk memahami lebih lanjut tentang pola dekorator dan penerapan satu contoh kehidupan nyata.