[問題] C++ 裝飾者模式給予參數問題

看板C_and_CPP (C/C++)作者 (f*******e)時間15年前 (2010/07/20 17:47), 編輯推噓0(009)
留言9則, 3人參與, 最新討論串1/1
( *[1m *[m 為色碼,可以按 Ctrl+V 預覽會顯示的顏色 ) ( 未必需要依照此格式,文章條理清楚即可 ) 遇到的問題: (題意請描述清楚) 最近在寫一個射擊的小遊戲, 在架構上一直有問題, 想麻煩各位版友指點. 最一開始是用 flyweight pattern + strategy pattern 來管理子彈. 所有同類子彈的資訊都由一個 BulletManager 類別統一儲存, 要繪圖或是更新狀態時, 將 BulletManager 儲存每個子彈的資訊的 vector 傳給一個 Bullet 類別一次處理完. 而 Bullet 對每個子彈的繪圖. 更新行為由 strategy pattern 來處理. 程式概略如下: class MyManager{ public: void UpdateBullets(){ UsingBullet->Update(BulletList); } private: Bullet * UsingBullet; vector<BulletStatus *> BulletList; }; class Bullet{ public: void Update(vector<BulletStatus *> & List){ MyUpdate->Update(List); } void Draw(vector<BulletStatus *> & List){ MyDraw->Draw(List); } private: UpdateBehavior * MyUpdate; DrawBehavoir * MyDraw; }; 但是隨著設計出來的花樣越來越多, 感覺 strategy pattern 的 concrete strategy 開始失控了. 舉例來說, 最一開始設計了一個直線子彈的 concrete strategy 但是到後來有的子彈是線性等速移動的, 但是有的是線性等加速度, 有的會在邊界反射一次, 有的只在左右邊界反射不在上下邊界反射... 這些性質排列組合, 感覺這樣 concrete strategy (UpdateBehavior)種類會成指數成長, 且儲存子彈資訊的類別要不跟著種類指數成長, 要不就會一直增肥, 裡面滿滿是不一定用到的參數. 所以想到改用 decorator pattern 來改寫. decorator pattern 的設計構想是 concrete component 負責儲存子彈資訊的 vector . 然後設計多種儲存資訊的類別, 在使用的時候要繼承過每個 decorator 需要的資訊 舉例來說資訊可能是這樣儲存: class BulletStatusBase{ public: float x, y; }; class BulletStatusFixedVelocity : public virtual BulletStatusBase{ public: float dx, dy; }; class BulletStatusReflect : public virtual BulletStatusBase { public: bool ReflectTop, ReflectBottom, ReflectLeft, ReflectRight; }; class MyBulletStatus : public BulletStatusFixedVelocity, public BulletStatusReflect{ }; 當初希望 concrete component 以 vector< BulletStatusBase * > 儲存 實際上是 MyBulletStatus 類別的物件, 當某個 Decorator 需要這個子彈有關反射的參數, 就將儲存的資料從 BulletStatusBase * 轉型成為 BulletStatusReflect * 然後取出有關反射的參數. 不過不管是靜態或動態轉型都不成功, 裝飾者模式寫到這裡卡住了. 想要請教各位板友正確的繼承與轉型方式, 或是其他解決這個問題的方法. 自己有想過兩個替代方案, 但是都覺得怪怪的: 1. BulletStatusBase 放上所有種類的 virtual getter . 一個是很不好看, 另一個對沒有這種屬性的物件, 應該要做甚麼反應呢? 2. 放棄 flyweight pattern , 直接把裝飾者模式套在每個子彈. 各種屬性直接放在 Decorator 上. 電腦跑不動吧... 所以還是來請教各位板友了. -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 218.170.54.29

07/20 19:59, , 1F

07/20 20:03, , 2F
第一點的設計不是很好, 雖然在等速度的子彈回傳加速度
07/20 20:03, 2F

07/20 20:04, , 3F
0 這類的方法在某些場合可以使用, 或是丟例外告訴使
07/20 20:04, 3F

07/20 20:05, , 4F
用者呼叫不合法...但並不是萬全之策
07/20 20:05, 4F

07/21 10:00, , 5F
可以請教love大分兩次dynamic cast的原因嗎?
07/21 10:00, 5F

07/21 11:24, , 6F
如果這個鑽石型的繼承樹不是用虛擬繼承, 直接往下轉就
07/21 11:24, 6F

07/21 11:24, , 7F
會模稜兩可, 我習慣都寫一樣的代碼
07/21 11:24, 7F

07/21 12:26, , 8F
原來如此, thx :D
07/21 12:26, 8F

07/21 14:56, , 9F
轉型成功了, 謝謝回答
07/21 14:56, 9F
文章代碼(AID): #1CHN2LA6 (C_and_CPP)
文章代碼(AID): #1CHN2LA6 (C_and_CPP)