提问人:Vahid 提问时间:10/27/2018 最后编辑:Vahid 更新时间:12/7/2022 访问量:337
C 语言中的相等性检查和向下转换代码味道#
Equality check and downcasting code smell in C#
问:
我有一个抽象基类 Shape,其中包含三个派生类:、 和 。我已经在这些类中实现了相等性检查,我想考虑是否具有相同的形状。为此,我检查 的类型,将其向下转换,然后执行其他检查以确定两者是否表示相同的几何图形。但是,我担心这种方法可能是一种代码异味,可能不是处理这种情况的正确方法。例如,如果有人将来要继承并创建一个可以与 具有相似形状的类,我目前的方法将不起作用。有没有更好的方法来处理这种情况?我当前的代码如下所示:Arc
Circle
Rectangle
Arcs
Circles
Shape
Shapes
Shape
Arc
public abstract class Shape : IEquatable<Shape>
{
public abstract bool Equals(Shape other);
}
public class Arc : Shape
{
public override bool Equals(Shape other)
{
if (other is Arc || other is Circle)
{
// Downcast and check for equality criteria!!
}
else
{
return false;
}
}
}
public class Circle : Shape
{
public override bool Equals(Shape other)
{
if (other is Arc || other is Circle)
{
// Downcast and check for equality criteria!!
}
else
{
return false;
}
}
}
public class Rectangle : Shape
{
public override bool Equals(Shape other)
{
if (other is Rectangle)
{
// Downcast and check for equality criteria!!
}
else
{
return false;
}
}
}
更新:
在考虑了答案并进一步思考之后,我认为我需要更改我的设计如下:类应该有像 和 这样的方法。然后,在类的相等性检查中,我可以写等等。这里显示的示例只是一个简化,以说明我在许多情况下遇到的问题。当然,这不是真正的代码Shape
IsEqualToCircle(Circle circle)
IsEqualToArc(Arc arc)
Arc
if (shape.IsEqualToArc(this)) return true;
答:
这似乎源于您的代表是多余的事实。与其直接向客户端类公开具体形状构造函数,不如让它们改用工厂方法。可以使用一个 CreateCircle 方法,该方法仅在内部创建 360° 圆弧,并完全删除 circle 类,或者有一个 CreateArc 方法,如果圆弧为 360°,则实际返回 Circle 实例,以最佳者为准。这样,你就永远不会有本应相等的不同类的实例。
评论
Line CreateLine()
PolyLine CreatePolyLine()
我会退后一步,想想你的课程。它们有什么共同点?显然,弧是一些线性特征,而圆形或矩形是面积特征。所以实际上它们有不同的维度,前者是一维的,而后者是二维的。那么,为什么将线要素与面积要素进行比较会返回相等性呢?
因此,恕我直言,更好的方法是有一些基本接口,例如,对于您定义方法的所有几何类型。如果两个形状具有相同的尺寸,则可以进一步比较它们。否则,它们就不相等。话虽如此,an 永远不等于 .但是,圆(如果您定义了这样的属性)可以作为 360° 的实例实现,可能等于 ,因为两者都是一维的。IGeometry
Equals
Arc
Circle
Boundary
Arc
Arc
评论
这整个设置是一种代码味道。两个不同类型的对象不应该相等,即使它们代表相同的现实。
有两种方法可以去这里:
隐式运算符
例如,这是如何返回;参数 Integer 隐式转换为浮点数,并且相等性检查成功。这并不是说该类以某种方式知道如何比较整数和双精度,它没有,它只知道如何比较 dohbles。
(1.0).Equals(1)
true
1
1.0
Double
请注意,这将失败,因为参数 double 不能隐式转换为整数;不同的类型...很奇怪,对吧?一种方式是真的,另一种方式不是......
1.Equals(1.0)
1.0
1
用户可以安全使用的显式转换机制。 可以有一种方法,可以在可能的情况下产生等效的圆,否则会失败。为了安全起见,还需要该属性来标记该方法是否可以安全调用。
Arch
ToCircle
IsCircle
评论
在 OOP 中,这类问题的教科书式解决方案是 Visitor 模式。我不是这个解决方案的忠实粉丝,因为它确实会带来很多开销,但它将使您能够进行多次调度,也就是说,基本上每个对或形状类型都有一种比较方法。这显然会导致很多代码,在这些代码中,您必须通过返回 false 等方式来声明一行永远不会等于圆,但是如果扩展性和低错误风险是您最关心的问题,那么它的好处是编译时检查任何新引入的 Shape 子类是否具有所有其他子类的比较方法。
评论
if (other is Rectangle rect) ...
Circle
Arc