2010-07-04 67 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