面向对象设计问题,Liskov替换原理

Sim*_*one 3 c++ oop

我正在设计一个OO框架,我面临着以下问题.

让我们说在框架中我有一个Shape接口,用户可以自由地实现和扩展(添加新函数)Shape接口来创建自己的数字,例如SquareCircle.要使这些新对象可用,用户必须将它们注册到ShapeFactory中,以指定形状(字符串)和对象的名称.

此外,该框架提供了一个名为ShapeWorker的接口,它定义了以下函数:

class ShapeWorker
{
public:
  void processShape( Shape& shape ) = 0;
};
Run Code Online (Sandbox Code Playgroud)

用户可以自由地实现ShapeWorker接口来制作特定的形状工作者,例如SquareWorkerCircleWorker.要使这些新对象可用,用户必须将它们注册到WorkerFactory,指定形状(字符串)和对象的名称.

在某个时刻,框架给定一个表示形状名称的字符串,通过使用ShapeFactory创建一个新的Shape,然后(代码中的其他地方)通过使用具有相同形状名称的WorkerFactory创建一个新的ShapeWorker.该processShape,然后调用提供的形状之前创建的实例.

[ ... ]
Shape* myShape = shapeFactory.create( shapeName );
[ ... ]
ShapeWorker* myWorker = workerFactory.create( shapeName );
myWorker->processShape( *myShape );
[ ... ]
Run Code Online (Sandbox Code Playgroud)

关键是,这样做,我强迫用户实现,例如,SquareWorkerShapeSquare进行向下转换为processShape函数,以便访问完整Square的界面:

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

这违反了利斯科夫的替代原则.

现在,这种做法是错误的吗?什么是更好的解决方案?请注意,我不想将processShape实现为Shape的成员函数.

我希望描述已经足够清楚了.

在此先感谢您的帮助.

西莫

jde*_*aan 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;
};
Run Code Online (Sandbox Code Playgroud)

这不需要实施者知道这种向下倾斜并且可能通过提供一些经常重用的功能来简化实现.