2010-07-04 69 views
3

我正在做一個OO框架的設計,我正面臨以下問題。面向對象的設計問題,Liskov替換原理

比方說,在框架中我有一個形狀界面,用戶可以自由地實現和擴展(添加新的功能)的形狀接口來創建自己的數字,例如Square and Circle。爲了使這些新對象可用,用戶必須將它們註冊到指定形狀(字符串)和對象的名稱的ShapeFactory中。

此外,框架提供了一個名爲ShapeWorker的接口定義瞭如下功能:

class ShapeWorker 
{ 
public: 
    void processShape(Shape& shape) = 0; 
}; 

在使用者自由地實現所述ShapeWorker界面,使特定形狀的工人,例如SquareWorker and CircleWorker。要使這些新對象可用,用戶必須將它們註冊到WorkerFactory中,指定形狀(字符串)和對象的名稱。

在某一點上,框架,賦予代表形狀的名稱的字符串,創建一個新的形狀,通過使用ShapeFactory,事後(代碼中的其他地方)創建一個新的ShapeWorker,通過使用具有相同形狀名稱的WorkerFactory。然後調用processShape提供以前創建的Shape實例。

[ ... ] 
Shape* myShape = shapeFactory.create(shapeName); 
[ ... ] 
ShapeWorker* myWorker = workerFactory.create(shapeName); 
myWorker->processShape(*myShape); 
[ ... ] 

的一點是,這樣做,我強迫實現用戶,例如,SquareWorker做出向下轉換從形狀廣場processShape功能,所以訪問完整的廣場的接口:

class SquareWorker 
{ 
public: 
    void processShape(Shape& shape) 
    { 
    Square& square = dynamic_cast< Square& >(shape); 
    // using Square interface 
    } 
}; 

這是對里氏替換原則。

現在,這種做法是錯誤的嗎?更好的解決方案是什麼?請注意,我不想執行processShape作爲形狀的成員函數。

我希望描述已經足夠清楚。

在此先感謝您的幫助。

廝磨

+1

你應該添加一個C++標籤我認爲。 – 2010-07-04 19:56:25

+0

您能否提供語句「請注意,我不想將processShape實現爲Shape的成員函數」的原因? – SCFrench 2010-07-04 22:14:13

+0

這裏的一個問題是,引用Shape和ShapeWorker的代碼不知道將形狀傳遞給ShapeWorker是否安全,沒有一些可追溯性返回到創建點來驗證兩個對象是使用相同的shapeName。 – SCFrench 2010-07-04 22:22:48

回答

5

除非你的形狀都必須由工人用一個通用的接口,這種做法似乎是完全正確的給我。形狀工作者或多或少地專注於特定的形狀,因此掌握了它所處理的類的知識。使用所有形狀的通用界面會更好,但不能將所需的所有東西都放入其中,最終會變得雜亂無章。向下轉換是解決這個問題的一個正確方法。

使用模板可以幫助你:你可以創建一個基類爲所有工人

template <class T> 
class BaseShapeWorker : ShapeWorker 
{ 
public: 
    void processShape(Shape& shape) 
    { 
    T& specificShape = dynamic_cast< T& >(shape); 
    processShape(specificShape) 
    } 
protected: 
    virtual void processShape(T& shape) = 0; 
}; 

這不會需要實施者瞭解這個沮喪的和可能還提供了一些經常緩解執行重用功能。

+1

+1。 NVI是一個很好的模式:) – 2010-07-04 22:04:33

+0

謝謝jdehaan,這是一個偉大的建議!這將簡化實施者的工作。 – Simone 2010-07-05 20:27:13