讓我們考慮一下。我相信你不僅有2個子表面,所以我們來概括一下。
首先想到的是代碼重複,可擴展性和親近性。讓我們來看看這些:
如果你想添加更多的類,你應該儘可能地改變代碼。
由於intersect
操作可交換,相交A
和B
應該在相同的位置的代碼,相交B
和A
,因此保持邏輯的類中的代碼本身是不可能的。另外,添加一個新的類並不意味着你必須修改現有的類,而是擴展一個委託類(是的,我們正在進入模式)。
這是當前的結構,我認爲(或類似的,可能是intersect
返回類型,但現在並不重要):
struct Primitive
{
virtual void intersect(Primitive* other) = 0;
};
struct Sphere : Primitive
{
virtual void intersect(Primitive* other)
};
struct Plane : Primitive
{
virtual void intersect(Primitive* other);
};
我們已經決定,我們不希望內部Plane
交集邏輯或Sphere
,所以我們創建了一個新的class
:
struct Intersect
{
static void intersect(const Sphere&, const Plane&);
//this again with the parameters inversed, which just takes this
static void intersect(const Sphere&, const Sphere&);
static void intersect(const Plane&, const Plane&);
};
在這裏,您將添加新功能的類和新的邏輯。例如,如果您決定添加Line
類,則只需添加方法intersec(const Line&,...)
。
請記住,添加新類時,我們不想更改現有的代碼。所以我們不能檢查相交函數中的類型。
我們可以爲該(策略模式)一類的行爲,其行爲不同,這取決於類型,我們可以事後擴展:
struct IntersectBehavior
{
Primitive* object;
virtual void doIntersect(Primitive* other) = 0;
};
struct SphereIntersectBehavior : IntersectBehavior
{
virtual void doIntersect(Primitive* other)
{
//we already know object is a Sphere
Sphere& obj1 = (Sphere&)*object;
if (dynamic_cast<Sphere*>(other))
return Intersect::intersect(obj1, (Sphere&) *other);
if (dynamic_cast<Plane*>(other))
return Intersect::intersect(obj1, (Plane&) *other);
//finally, if no conditions were met, call intersect on other
return other->intersect(object);
}
};
而在我們原來的方法,我們就必須:
struct Sphere : Primitive
{
virtual void intersect(Primitive* other)
{
SphereIntersectBehavior intersectBehavior;
return intersectBehavior.doIntersect(other);
}
};
一個更清潔的設計將實現一個工廠,抽象出實際類型的行爲:
struct Sphere : Primitive
{
virtual void intersect(Primitive* other)
{
IntersectBehavior* intersectBehavior = BehaviorFactory::getBehavior(this);
return intersectBehavior.doIntersect(other);
}
};
,你甚至不需要intersect
是虛擬的,因爲它只是爲每個班級做這個。
如果在添加新的類時,遵循這一設計
- 無需修改現有代碼
- 有一個地方的實現
- 只
IntersectBehavior
爲每個新類型
- 延長在
Intersect
類中提供新類型的實現
我敢打賭,這可能會進一步完善。
如果你想要多態性爲什麼你想要一個靜態類型?在你的界面中使用基類指針,並讓它在運行時動態地找出類型。這是虛擬方法的重點。 – AJG85
你會怎樣稱呼虛擬靜態? –
我正在考慮通過一個實例進行調用,例如[http://stackoverflow.com/questions/325555/c-static-member-method-call-on-class-instance],甚至通過'this'指針,例如[http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fcplr039.htm] – wsaleem