关于c++ class 接口设计的建议:你会如何命名这两个方法以使其显而易见?
Advice on c++ class interface design: how would you name these two methods to make them obvious?
我有一个非常简单的具体 class 表示 2D 中的一个点 space,它有两种方法可以在给定半径和角度的情况下移动点:一种修改对象本身, other 创建另一个对象,保持第一个不变:
template<class T =double> class cls_2DPoint
{
...
cls_2DPoint<T>& polar_move(const T r, const double a) noexcept
{
x+=r*std::cos(a); y+=r*std::sin(a); return *this;
}
cls_2DPoint<T> polar_moved(const T r, const double a) const noexcept
{
return cls_2DPoint<T>(x+r*std::cos(a), y+r*std::sin(a));
}
...
T x,y;
};
这实际上是我正在使用的代码!在审查它时,我意识到这是一个鲁莽的设计:不明显,容易出错,使用户代码的可读性降低。
由于我正在努力寻找一个令人信服的替代方案,所以我想在这里征求意见:是否有通用的 conventions/guidelines 用于命名修改和非修改方法?是否有可以帮助我改进设计的最佳实践?
我的建议。
使用 namespace
代替 class 名称的前缀
namespace cls2D
{
class Point { ... };
}
添加classVector
namespace cls2D
{
class Point { ... };
class Vector { ... };
}
定义运算符方法
定义适用于两种对象类型的运算符方法。如果可以的话,最好使用非成员函数。
namespace cls2D
{
class Vector;
class Point
{
public:
Point& operator+=(Vector v);
Point& operator-=(Vector v);
private:
double x = 0;
double y = 0;
};
class Vector
{
public:
Vector& operator+=(Vector v);
Vector& operator-=(Vector v);
private:
double x = 0;
double y = 0;
};
Point from_polar(double r, double th);
Point from_vector(Vector v);
Vector from_point(Point p);
Point operator+(Point p, Vector v);
Point operator+(Vector v, Point p);
Vector operator+(Vector v1, Vector v2);
Vector operator-(Point p1, Point p2);
Vector operator-(Vector v1, Vector v2);
}
请注意Point
和Vector
有相同的成员数据。因此,很容易只使用一个 class 来表示两者。但是,我认为它们是两个不同的抽象,应该是不同的 classes.
我删除了回答中的 template
部分,以便更简单地说明这个想法。
我假设您知道如何将必要的构造函数添加到 classes。
我会这样命名它们:
template<class T =double> class cls_2DPoint
{
...
cls_2DPoint<T>& polarMovePoint(const T r, const double a) noexcept
{
x+=r*std::cos(a); y+=r*std::sin(a); return *this;
}
cls_2DPoint<T> polarMovePointClone(const T r, const double a) const noexcept
{
return cls_2DPoint<T>(x+r*std::cos(a), y+r*std::sin(a));
}
...
T x,y;
};
这种类型的标签会让我知道哪个函数移动了点本身,哪个函数创建了点的克隆然后移动了那个点。
我有一个非常简单的具体 class 表示 2D 中的一个点 space,它有两种方法可以在给定半径和角度的情况下移动点:一种修改对象本身, other 创建另一个对象,保持第一个不变:
template<class T =double> class cls_2DPoint
{
...
cls_2DPoint<T>& polar_move(const T r, const double a) noexcept
{
x+=r*std::cos(a); y+=r*std::sin(a); return *this;
}
cls_2DPoint<T> polar_moved(const T r, const double a) const noexcept
{
return cls_2DPoint<T>(x+r*std::cos(a), y+r*std::sin(a));
}
...
T x,y;
};
这实际上是我正在使用的代码!在审查它时,我意识到这是一个鲁莽的设计:不明显,容易出错,使用户代码的可读性降低。 由于我正在努力寻找一个令人信服的替代方案,所以我想在这里征求意见:是否有通用的 conventions/guidelines 用于命名修改和非修改方法?是否有可以帮助我改进设计的最佳实践?
我的建议。
使用 namespace
代替 class 名称的前缀
namespace cls2D
{
class Point { ... };
}
添加classVector
namespace cls2D
{
class Point { ... };
class Vector { ... };
}
定义运算符方法
定义适用于两种对象类型的运算符方法。如果可以的话,最好使用非成员函数。
namespace cls2D
{
class Vector;
class Point
{
public:
Point& operator+=(Vector v);
Point& operator-=(Vector v);
private:
double x = 0;
double y = 0;
};
class Vector
{
public:
Vector& operator+=(Vector v);
Vector& operator-=(Vector v);
private:
double x = 0;
double y = 0;
};
Point from_polar(double r, double th);
Point from_vector(Vector v);
Vector from_point(Point p);
Point operator+(Point p, Vector v);
Point operator+(Vector v, Point p);
Vector operator+(Vector v1, Vector v2);
Vector operator-(Point p1, Point p2);
Vector operator-(Vector v1, Vector v2);
}
请注意Point
和Vector
有相同的成员数据。因此,很容易只使用一个 class 来表示两者。但是,我认为它们是两个不同的抽象,应该是不同的 classes.
我删除了回答中的 template
部分,以便更简单地说明这个想法。
我假设您知道如何将必要的构造函数添加到 classes。
我会这样命名它们:
template<class T =double> class cls_2DPoint
{
...
cls_2DPoint<T>& polarMovePoint(const T r, const double a) noexcept
{
x+=r*std::cos(a); y+=r*std::sin(a); return *this;
}
cls_2DPoint<T> polarMovePointClone(const T r, const double a) const noexcept
{
return cls_2DPoint<T>(x+r*std::cos(a), y+r*std::sin(a));
}
...
T x,y;
};
这种类型的标签会让我知道哪个函数移动了点本身,哪个函数创建了点的克隆然后移动了那个点。