Объектно-ориентированная задача проектирования, принцип подстановки Лискова - PullRequest
3 голосов
/ 04 июля 2010

Я делаю дизайн OO-фреймворка и сталкиваюсь со следующей проблемой.

Допустим, в фреймворке у меня есть Shape интерфейс и пользователи свободныреализовывать и расширять (добавляя новые функции) интерфейс Shape для создания собственных фигур, например Square и Circle .Чтобы сделать эти новые объекты доступными, пользователи должны зарегистрировать их в ShapeFactory с указанием имени фигуры (строки) и объекта.

Кроме того, инфраструктура предоставляет интерфейс под названием ShapeWorker , который определяет следующую функцию:

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

Пользователи могут свободно реализовывать интерфейс ShapeWorker , чтобы сделать конкретную рабочую фигуру, например, SquareWorker и CircleWorker .Чтобы сделать эти новые объекты доступными, пользователи должны зарегистрировать их в WorkerFactory , указав имя формы (строки) и объекта.

В определенный момент каркас, учитываяСтрока, представляющая имя фигуры, создает новую Shape , используя ShapeFactory , а затем (где-то еще в коде) создает новую ShapeWorker , используя WorkerFactory с тем же именем фигуры.Затем вызывается processShape , обеспечивающий созданный ранее экземпляр Shape .

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

Дело в том, что, делая это, я заставляю пользователя, например, реализовывать SquareWorker для выполнения преобразования с Shape до Square в processShape , чтобы получить доступ к полной SquareИнтерфейс :

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

Это противоречит принципу подстановки Лискова.

Теперь, этот подход неправильный?Какое это было бы лучшее решение?Обратите внимание, что я не хочу реализовывать processShape как функцию-член Shape .

Надеюсь, описание достаточно ясное.

Заранее благодарим за вашепомощь.

Симо

1 Ответ

5 голосов
/ 05 июля 2010

Если ваши фигуры не имеют общего интерфейса, который должны использоваться рабочими, этот подход кажется мне полностью правильным. Формовщик более или менее специализируется на конкретной форме, поэтому знает о классе, с которым он работает. Было бы лучше сделать это, используя общий интерфейс для всех форм, но вы не можете поместить в него все, что вам понадобится, в конечном итоге это будет полностью загромождено. Даункинг - верное средство для решения этой проблемы.

Вам может помочь использование шаблонов: вы можете создать базовый класс для всех работников

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;
};

Для этого разработчикам не нужно знать об этом унынии и упростить реализацию, возможно, также предоставив некоторые часто используемые функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...