iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0
Software Development

深入淺出設計模式 - 使用 C++系列 第 4

[Day 04] 為愛用繼承的人設計一對眼睛 - 裝飾器模式 (Decorator Pattern)

  • 分享至 

  • xImage
  •  

裝飾器模式 (Decorator Pattern)

可以動態地為物件附加額外的職責。使用裝飾器來擴展功能比使用繼承更有彈性
Head First Design Patterns, 2nd (p.91)

  • 定義
    • Decorator is a structural pattern that allows adding new behaviors to objects dynamically by placing them inside special wrapper objects, called decorators
  • 元素組成
    • Component
      The base Component interface defines operations that can be altered by decorators
    • ConcreteComponent
      Concrete Components provide default implementations of the operations. There might be several variations of these classes
    • Decorator
      The base Decorator class follows the same interface as the other components. The primary purpose of this class is to define the wrapping interface for all Concrete Decorator
    • Concrete Decorators
      Concrete Decorators call the wrapped object (Decorator) and alter its result
  • 筆記
    • 開放 / 封閉原則: 類別應該容易擴展,但不會改變到既有舊功能
    • 遵守「開放/封閉原則」通常會引入新一層的抽象,讓程式更複雜,故應該把注意力放在最有可能改變的地方
    • 謹慎選擇要擴展的部分,到處採用此原則不但浪費,也沒必要,甚至可能寫出更複雜、難以理解的程式!
      • 缺點: 使用裝飾器,會產生大量的小類別,造成更多資源耗損
    • 在撰寫測試程式時,要注意針對抽象Component型態撰寫測試,而非具體Component,否則被包在裝飾器內部的物件可能會較難測試
    • 使用裝飾器,必須管理更多物件,更容易寫錯程式 (回傳錯層 Reference...等)。為了妥善封裝,通常會和工廠(Factory)或建造者(Builder)模式結合

範例 (與書本不同)

https://ithelp.ithome.com.tw/upload/images/20230916/201386432rwpwNcyh7.png

// DecoratorPattern.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
#include <iostream>
 
class IiceCream
{
public:
    virtual void Make() = 0;
    virtual ~IiceCream() { }
 
};
 
class SimpleIceCream: public IiceCream
{
public:
    virtual void Make() 
    {
        std::cout<<"\n milk + sugar +  Ice cream Powder";
    }
 
 
};
 
class IceCreamDecorator: public IiceCream
{
 
public:
    IceCreamDecorator(IiceCream& decorator):m_Decorator(decorator)
    {
 
    }
 
    virtual void Make() 
    {
        m_Decorator.Make();
    }
    private:
    IiceCream& m_Decorator;
};
 
class WithFruits : public IceCreamDecorator
{
 
public:
     WithFruits(IiceCream& decorator):IceCreamDecorator(decorator)
     {
 
     }
     virtual void Make() 
     {
         IceCreamDecorator::Make();
         std::cout<<" + Fruits";
     }
 
};
 
class WithNuts : public IceCreamDecorator
{
 
public:
    WithNuts(IiceCream& decorator):IceCreamDecorator(decorator)
    {
 
    }
 
    virtual void Make() 
    {
        IceCreamDecorator::Make();
        std::cout<<" + Nuts";
    }
 
};
 
class WithWafers : public IceCreamDecorator
{
 
public:
    WithWafers(IiceCream& decorator):IceCreamDecorator(decorator)
    {
 
    }
 
    virtual void Make() 
    {
        IceCreamDecorator::Make();
        std::cout<<" + Wafers";
    }
 
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    IiceCream* pIceCreamSimple = new SimpleIceCream();
    pIceCreamSimple->Make();
 
    IiceCream* pIceCreamFruits = new WithFruits(*pIceCreamSimple);
    pIceCreamFruits->Make();
 
    IiceCream* pIceCreamNuts   = new WithNuts(*pIceCreamFruits);
    pIceCreamNuts->Make();
 
    IiceCream* pIceCreamWafers = new WithWafers(*pIceCreamNuts);
    pIceCreamWafers->Make();
 
    delete pIceCreamSimple;
    delete pIceCreamFruits;
    delete pIceCreamNuts;
    delete pIceCreamWafers;
 
    return 0;
}

Reference

[1]. https://refactoring.guru/design-patterns/decorator/cpp/example
[2]. https://cppcodetips.wordpress.com/2016/10/31/decorator-pattern-explained-with-c-sample/
[3]. https://www.bogotobogo.com/DesignPatterns/decorator.php


上一篇
[Day 03] 把會變的部分封裝 - 策略模式 (Strategy Pattern)
下一篇
[Day 05] 烘焙物件的精華 - 工廠模式 (Factory Pattern)
系列文
深入淺出設計模式 - 使用 C++37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言