Раздутый интерфейс нуждается в обрезке - PullRequest
1 голос
/ 09 июля 2011

Извините за плохой заголовок, я не мог придумать более описательный.

Имеющийся у меня Shape ADT постоянно увеличивается и становится более раздутым, особенно из-за этого раздела интерфейса:

 
class Shape() {
    //...
    virtual bool Intersects(const Point& point) const =0;
    virtual bool Intersects(const Line& line) const =0;
    virtual bool Intersects(const Line& line, bool isInfinite) const =0;
    virtual bool Intersects(const Rectangle& rectangle) const =0;
    virtual bool Intersects(const Circle& circle) const =0;
    virtual bool Intersects(const Ellipse& ellipse) const =0;
    virtual bool Intersects(const Triangle& triangle) const =0;
    virtual bool Intersects(const Arc& arc) const =0;
    //...
};
 

каждый новый класс, который подклассы Shape должен быть добавлен в интерфейс.Это быстро стареет.Я помню, как читал где-то, что для решения проблемы был шаблон дизайна.О шаблонах не может быть и речи: каждая фигура имеет свой собственный уникальный способ обнаружения пересечения с разными объектами, поэтому он не лучше, чем то, что делается в настоящее время.

Ответы [ 3 ]

4 голосов
/ 09 июля 2011

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

У вас есть два объекта, каждый из которых имеет неопределенный тип, но вы знаете, что он находится над конечным набором типов. Теперь вы хотите вызвать функцию, которая выполнит некоторую операцию над ними двумя. И реализация этой функции будет меняться в зависимости от пары типов; оно не основано только на одном типе или другом.

ООП тебе здесь не поможет. Вам нужен другой дизайн для этого. Что вам нужно, это список функций, которые выполняют пересечения между различными допустимыми парами типов. Затем вы используете функцию диспетчеризации для индексации в этой таблице на основе двух типов во время выполнения. Поэтому вам нужно немного кода RTTI, чтобы получить индекс типа или что-то, что вы можете использовать для отправки на основе.

4 голосов
/ 09 июля 2011

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

Второе, что нужно понять, это то, что это проблема n ^ 2, или, точнее, n * (n + 1) / 2. Каждый раз, когда вы добавляете новую фигуру, вы должны добавить функцию пересечения для каждой из предыдущих n фигур. Очевидно, это не масштабируется, поэтому вы обратились за помощью.

В реальном мире способ решения этой проблемы состоит в том, чтобы придумать меньшее количество классов, которые могут выступать в качестве надмножества некоторых фигур. Например, ваша Точка, Линия, Прямоугольник и Треугольник могут быть выражены как набор отрезков линии; Ваш Круг может быть Дугой, которая покрывает 360 градусов. Если точность не требуется, вы можете аппроксимировать каждую отдельную фигуру в виде набора кривых Безье и иметь единственный метод Intersect, который знает коллекцию.

2 голосов
/ 09 июля 2011

Точка, Линия, Прямоугольник, Круг, Эллипс, Треугольник и Дуга - все это «Геометрия» - вам не хватает базового класса.Или это общий базовый класс "Shape"?Если это так, у вас есть еще больше проблем (интерфейс Shape знает о его реализации).

Я бы создал общий базовый класс и объявил бы один виртуальный метод пересечения.Вероятно, вы могли бы использовать шаблон посетителя для реализации фактической логики пересечений без знания базовым классом всех различных реализаций.

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