8

这个问题在我的职业生涯中多次出现,并将我和我的同事分成两个阵营。我认为这可能是这个网站上最好的答案,一劳永逸。

几乎所有图形 UI 库都实现了 Rectangle 结构,但它们的实现方式通常分为两个可能的选项:

  1. 矩形定义为同一坐标系内的两个二维点,通常命名为 p0 和 p1,或具有单独的分量,如 x0、y0、x1、y1。
  2. 矩形被定义为 2D 原点和大小向量,通常命名为位置和大小,或者单独命名为 x、y、宽度、高度。

现在,假设我要编写一个 UI 库,我应该选择两种选择中的哪一种?

更新:问题涉及实现,而不是接口。当然,矩形的界面可以很好地支持这两种方法,但是如何在矩形中存储数据呢?

4

2 回答 2

8

为什么不两者都选?

真的,唯一重要的是你的库和它的内部之间的接口。或者,您的用户将如何使用该库。您可以根据需要存储矩形的信息,但是应该将其封装在远离用户的地方,这样他们就不必担心矩形是如何存储的,只是它确实是一个矩形。

换句话说,选择两者,如果您正在编写面向对象的代码,您可以根据需要存储矩形,然后让您的用户使用任何一种方法创建一个矩形。

例如,您的声明可能如下所示:

class Rectangle
{
public:
    Rectangle(Point p1, Point p2);
    Rectangle(Point origin, int width, int height);
    ...
};

(C++,因为你标记了那个)

Point 是一些类:

class Point
{
public:
    Point(int x, int y) : mX(x), mY(y) {}
private:
    int mX;
    int mY;
};

这样,您的库不仅限于支持一种类型的规范来创建矩形。

就具体实现而言,这真的无关紧要。它们都可以工作并且可以很容易地相互转换并使用相同数量的内存,因此使用一个比另一个不会对性能产生重大影响。

为了简化开发,请考虑矩形的用例是什么。查看您需要为该类编写的每个成员函数,并考虑哪种格式可以更轻松地编写这些函数。

如果是我,我可能会用这两点来实现它。

编辑:为什么我认为以任何一种方式实施它的学术方法在大多数情况下都绝对没有区别。

让我们的 Rectangle 类上有一个成员函数或一个操作,它可以在我们的矩形上工作或进行一些计算。假设一种实现方法(宽度/高度/原点或两点)将比另一种实现更快地执行此操作。

我们可以使用以下实现从实现宽度/高度/原点转换:

// assuming x0,y0 is top left and x1,y1 is bottom right
x0 = originX;
y0 = originY;
x1 = originX + width;
y1 = originY + height;

我们可以从实现转换为以下两点:

// assuming x0,y0 is top left and x1,y1 is bottom right
originX = x0;
originY = y0;
width = x1 - x0;
height = y1 - y0;

因此,执行此操作比其他实现慢得多/差得多的实现可以在 O(1) 运行时间内转换为其他实现,因此其他实现不能第一个实现好得多。

除非您每秒执行数千次此操作或在性能极其有限的设备上执行此操作,否则我非常相信不会有性能差异。已经没有内存差异,因为这两种实现几乎都只存储 4 个浮点数/整数。

这几乎留下了编码的便利,就像我在上面的原始帖子中所说的那样,您可以简单地“考虑一下矩形的用例是什么。看看您需要为该类编写的每个成员函数并思考关于哪种格式会使编写这些函数更容易。”

于 2012-04-05T10:14:04.750 回答
2

毫无疑问,这当然完全取决于您面临的问题。

对于图形绘图算法,第二个选项似乎有一个非常小的优势恕我直言。而对于在欧几里得平面上定义的一般“几何”算法 - 第一个选项更方便一些。

此外,有一次我正在研究在地球表面定义的算法。意味着,x,y 坐标分别代表经度/纬度。x坐标显然是循环的。在这种特定情况下,为了定义(某种)矩形 - 仅定义角是不够的,您还需要一个方向。这可以通过第一个点 (p0) 是最左边的点,而第二个点 (p1) - 最右边的约定来处理。但我更喜欢切换到第二个约定,在那里你自然有一个角和一个偏移向量。

于 2012-04-05T10:21:01.140 回答