Menu
CoddyTech

Pola Decorator

Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 98 dari 104.

Pola Decorator memungkinkan kamu menambahkan perilaku baru ke object secara dinamis dengan membungkusnya dalam object khusus yang disebut decorator. Tidak seperti pewarisan, yang menambahkan perilaku saat kompilasi, decorator memungkinkan kamu memperluas fungsionalitas saat runtime tanpa mengubah class asli.

Pola ini bekerja dengan membuat object asli dan decorator mengimplementasikan interface yang sama. Setiap decorator menyimpan referensi ke sebuah komponen dan menambahkan perilakunya sendiri sebelum atau sesudah meneruskan panggilan ke object yang dibungkus:

#include <iostream>
#include <memory>

// Antarmuka komponen
class Coffee {
public:
    virtual std::string getDescription() const = 0;
    virtual double getCost() const = 0;
    virtual ~Coffee() = default;
};

// Komponen konkret
class SimpleCoffee : public Coffee {
public:
    std::string getDescription() const override { return "Coffee"; }
    double getCost() const override { return 2.0; }
};

// Dekorator dasar
class CoffeeDecorator : public Coffee {
protected:
    std::unique_ptr<Coffee> coffee;
public:
    CoffeeDecorator(std::unique_ptr<Coffee> c) : coffee(std::move(c)) {}
};

// Dekorator konkret
class MilkDecorator : public CoffeeDecorator {
public:
    MilkDecorator(std::unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}
    std::string getDescription() const override {
        return coffee->getDescription() + ", Milk";
    }
    double getCost() const override { return coffee->getCost() + 0.5; }
};

class SugarDecorator : public CoffeeDecorator {
public:
    SugarDecorator(std::unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}
    std::string getDescription() const override {
        return coffee->getDescription() + ", Sugar";
    }
    double getCost() const override { return coffee->getCost() + 0.2; }
};

Decorator dapat ditumpuk, setiap decorator membungkus decorator sebelumnya, sehingga fungsionalitas bertambah lapis demi lapis:

int main() {
    std::unique_ptr<Coffee> order = std::make_unique<SimpleCoffee>();
    order = std::make_unique<MilkDecorator>(std::move(order));
    order = std::make_unique<SugarDecorator>(std::move(order));
    
    std::cout << order->getDescription() << ": $" << order->getCost();
    // output: Coffee, Milk, Sugar: $2.7
}

Gunakan Decorator saat kamu perlu menambahkan tanggung jawab ke object secara dinamis tanpa memengaruhi object lain, atau saat memperluas fungsionalitas melalui subclassing akan menyebabkan jumlah class meningkat drastis.

challenge icon

Tantangan

Mudah

Mari kita bangun Sistem Pemesanan Pizza menggunakan pola Decorator. Kamu akan membuat sistem fleksibel yang memungkinkan pelanggan memulai dengan pizza dasar dan menambahkan berbagai topping: setiap topping membungkus pesanan sebelumnya dan menambahkan biaya serta deskripsinya sendiri. Ini adalah kasus penggunaan yang sempurna untuk decorator: topping dapat ditumpuk dalam kombinasi apa pun tanpa membuat jumlah subclass membengkak.

Kamu akan mengatur kodemu dalam tiga file:

  • Pizza.h: Definisikan interface komponen dan class pizza dasar.

    Buat class abstrak Pizza dengan method virtual murni getDescription() (mengembalikan string) dan getCost() (mengembalikan double), serta destructor virtual.

    Lalu buat class konkret PlainPizza yang merepresentasikan pizza dasar. Class ini harus mengembalikan "Pizza" sebagai deskripsinya dan memiliki biaya dasar 8.0.

  • ToppingDecorator.h: Buat class dasar decorator dan decorator topping konkret.

    Buat class ToppingDecorator yang mewarisi Pizza dan menyimpan std::unique_ptr<Pizza> ke komponen yang dibungkus. Class ini menjadi dasar untuk semua decorator topping.

    Implementasikan tiga decorator topping konkret:

    • CheeseTopping: menambahkan ", Cheese" ke deskripsi dan 1.5 ke biaya
    • PepperoniTopping: menambahkan ", Pepperoni" ke deskripsi dan 2.0 ke biaya
    • MushroomTopping: menambahkan ", Mushrooms" ke deskripsi dan 1.0 ke biaya

    Setiap decorator harus meneruskan pemanggilan ke pizza yang dibungkus, lalu menambahkan kontribusinya sendiri.

  • main.cpp: Buat pesanan pizza yang disesuaikan berdasarkan input pengguna.

    Baca tiga input (masing-masing berupa yes atau no):

    1. Tambahkan keju?
    2. Tambahkan pepperoni?
    3. Tambahkan jamur?

    Mulai dengan PlainPizza, lalu bungkus dengan decorator topping yang sesuai berdasarkan input (dengan urutan: keju, pepperoni, jamur). Terakhir, cetak detail pesanan dengan format berikut:

    Order: [description]
    Total: $[cost]

Contohnya, dengan input yes, yes, no:

Order: Pizza, Cheese, Pepperoni
Total: $11.5

Dengan input yes, no, yes:

Order: Pizza, Cheese, Mushrooms
Total: $10.5

Dengan input no, no, no:

Order: Pizza
Total: $8

Dengan input yes, yes, yes:

Order: Pizza, Cheese, Pepperoni, Mushrooms
Total: $12.5

Perhatikan bagaimana setiap decorator membungkus decorator sebelumnya, menyusun deskripsi dan biaya lapis demi lapis. Kamu dapat dengan mudah menambahkan topping baru dengan membuat class decorator baru tanpa mengubah kode pizza atau topping yang sudah ada. Itulah keunggulan pola Decorator.

Coba sendiri

#include <iostream>
#include <string>
#include <memory>
#include "Pizza.h"
#include "ToppingDecorator.h"

using namespace std;

int main() {
    // Baca tiga input (yes atau no)
    string addCheese, addPepperoni, addMushrooms;
    cin >> addCheese;
    cin >> addPepperoni;
    cin >> addMushrooms;
    
    // TODO: Mulai dengan PlainPizza menggunakan std::unique_ptr
    
    // TODO: Jika addCheese bernilai "yes", bungkus pizza dengan CheeseTopping
    
    // TODO: Jika addPepperoni bernilai "yes", bungkus pizza dengan PepperoniTopping
    
    // TODO: Jika addMushrooms bernilai "yes", bungkus pizza dengan MushroomTopping
    
    // TODO: Tampilkan pesanan dalam format:
    // Pesanan: [description]
    // Total: $[cost]
    
    return 0;
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Object

Latihan sendiri: Compiler C++ online