案例:
戰鬥模式類似 國王的恩賜 , 有 世界情境 和戰鬥情境。 當碰到世界情境的 怪物之後 , 切換到戰鬥情境進行戰鬥。如何處理2個情境的怪物的屬性,使它們能夠正確的顯示。
問題存在的理由:
1、世界情境 和 戰鬥情境 的怪物 在表現層上是一致的, 但是在資料層上是不一致的。 戰鬥情境的 怪物在屬性資料上將更加詳細和特殊, 而世界情境上的怪物也不能只是具有表現層ID,需要一部分 屬性資料用來顯示資訊(UI)。
2、由於 我們 給策劃提供的 Execl 匯出工具 不提供 匯出子表的功能, 而且 世界情境怪物 和 戰鬥情境怪物 的屬性 是相交 而不是 子集的關係(具體屬性執行個體大家參考第1條自行想象..想象)。
3、顯示 生物模型 是一個相對獨立的模組,它需要傳遞3D表現參數,而不關係 這些參數是 來自世界情境對象 或者 戰鬥情境對象, 或者火星對象。
問題核心分析:
無疑 兩種屬性資料結構都包含了 3D表現 相關的 資料資訊。
而且在這裡我們只是希望從這些重疊部分中提取 3D表現 相關的資料資訊。
所以我們需要解決的問題是 如何從 2個相似 的怪物屬性資料中 提取重疊的 3D表現部分。
推廣後可以得到問題的本質: 如何從 相交的 資料對象中 提取重疊的資料。
解決方案分析:
在看到 問題存在理由1 的時候,基本上就可以確定“將公用屬性提出來,作為基類 怪物屬性,然後派生 世界情境怪物屬性, 和 戰鬥情境怪物屬性” 的解決方案。
再考慮 第2條理由之後, 為了配合上述方案,需要更改匯出表。但再仔細考慮,其實我們只需要一個能夠作為公用屬性的子表,而不在意其來源。 (子任務一)
再將 子任務一 的因素加進來考慮 , 進行分析,有2個解決方案
方案一 : 基於 擴充 Execl 匯出工具
1、擴充 Execl 匯出工具 , 使之支援 屬性項的自由組合匯出(最進階別) 或者 匯出子表(最低層級)。
2、修改怪物屬性類 的結構, 使之 滿足需求。
方案二: 不修改Execl ,完全由程式解決。
該方案本質上來說就是 由程式這頭從 代碼上解決問題。
比較兩者的花費:
方案一 影響到了 2個部門, 對策劃來說,工作流程受到了影響, 最顯著的特徵就是 增加了策劃 在產出資料時的 工作量(選擇哪些是公用的)。對程式來說,需要擴充匯出工具(這個工作量還是有一些的)。
方案二 影響一個部門(其實就是偶 囧),時間2小時-1天(視該屬性涉及到的介面 ,包括 Server 和 Client 之間的通訊)。
比較兩者的優勢:
方案一 完善了匯出工具
方案二 時間成本小, 出效果快
在這裡 我傾向於第2種方案, 因為有個前提:進度進度進度 囧囧。
OK。關於第2個方案,我的實現是:
struct 3D表現資料 // 表現層關心的資料
{
A;
B;
};
class IMonsterAttribute // 搜集資料的介面層
{
public:
virtual 3D表現資料 getData() const = 0;
virtual void setData( const 3D表現資料& ) = 0;
};
// 資料來源一: 世界情境怪物屬性, 給它套個介面,並實現。
class WorldMonsterAttribute : public IMonsterAttribute
{
public:
各種資料;
A;
B;
C;
E;
public:
3D表現資料 getData() const
{
3D表現資料 data;
data.A = A;
data.B = B;
return data;
}
void setData( const 3D表現資料& data)
{
A = data.A;
B = data.B;
}
};
// 資料來源二: 戰鬥情境怪物屬性, 給它套個介面,並實現。
class BattleMonsterAttribute : public IMonsterAttribute
{
public:
各種資料;
A;
B;
F;
G;
public: // 介面實現(略)
};
class Monster
{
public:
void load( const IMonsterAttribute* pData)
{
if( pData == NULL)
return;
3D表現資料 data;
pData->getData(data);
// OK, 在這裡我們得到了關心的資料,可以做任何事了:
ShowBody( data.A);
ShowWeapon( data.B);
ShowAss( data.Ass);
PlayAction( data.KickAss);
}
};