如何设计形状类形状

2023-09-07 00:11:38 作者:琴瑟仙男卢西奥

我想设计形状类。我需要区分几种不同的形状:

I want to design shape class. I need to distinguish several different shapes:

-Point  
-Line  
-Triangle  
-Circle  
-Polygons  

这个类的主要目的是计算两个形状之间的距离。 我已经为计算这些距离的所有方法,但我希望有一个可以使用的一个方法,它应该是这样的:

The main purpose of this class is to calculate distance between two shapes. I've all methods for calculating those distances, but I want to have a single method that can be used, it should looks like this:

float Distance(Shape a, Shape b)

最简单的做法是把if语句很多,然后调用适当的方法,但这是deffinitely不是面向对象。

Simplest way to do it is to put a lot of if statements and then invoke proper method but this is deffinitely not OOP.

如何设计这样的类在面向对象的风格呢?

How to design such class in OOP style?

推荐答案

这是一个棘手的问题,因为如果你正在实施的方法来计算使用的最近点两个物体之间的距离,你真的需要知道是什么类型的两个的对象。如果使用例如中心点比较,那么这将是很容易 - 你只需要添加 GetCenter 的方法,但是这根本就不在这种情况下工作。

This is a tricky problem, because if you're implementing the method to calculate distance between two objects using the nearest point, you really need to know what are the types of both of the objects. If you were comparing it using for example the center point, then it would be easy - you'd just add GetCenter method, but that simply doesn't work in this case.

的问题是,类层次结构是有用的,如果可以设计出它们作为可扩展的 - 也就是说,允许加入其它类型的,而无需修改现有的。这不是这里的情况,因为当你添加椭圆您需要实现 DistancePointEllipse DistanceTriangleEllipse ,等等...这将是更容易重新present此使用的代数数据类型从函数式语言知。例如,在F#:

The problem is that class hierarchies are useful if you can design them as extensible - that is, allow adding of other types without modifying the existing ones. This is not the case here, because when you add Ellipse you'll need to implement DistancePointEllipse, DistanceTriangleEllipse, and so on... It would be much easier to represent this using algebraic data type known from functional languages. For example in F#:

type Shape = 
  | Circle of float * float * float // center & radius
  | Point of float * float          // center

然后就可以使用模式匹配来处理所有可能的情况:

Then you could use pattern matching to handle all possible cases:

match shape1, shape2 with
| Circle(x1, y1, r1), Circle(x2, y2, r2) -> // two circles
| Point(x1, y1), Point(x2, y2) -> // two points
| Circle(cx, cy, r), Point(px, py) 
| Point(px, py), Circle(cx, cy, r) ->
    // point and a circle (both combinations

函数式编程只是似乎是这个问题更适合: - )

Functional programming simply seems to be a better fit for this problem :-).

总之,一个可能的(但仍非extensibel)面向对象的设计将有图形与方法的基础类 DistanceToPoint DistanceToTriangle 等的计算从目前的类型到另一种形状的距离(如你真的需要所有的组合)。

Anyway, one possible (but still non-extensibel) object-oriented design would be to have Shape base class with methods DistanceToPoint, DistanceToTriangle, etc. that calculate the distance from the current type to the other type of shape (as you really need all the combinations).

另一种方法是简单地写在C#中重载的方法:

Another approach would be to simply write overloaded method in C#:

float Distance(Triangle t, Point p);
float Distance(Triangle t, Circle c);
// ... etc

有关此选项的好处是,你可以很容易地减少你需要写的方法数。例如,如果你有椭圆,你可以继承圆从椭圆,然后利用现有的情况下,

The nice thing about this option is that you could easily reduce the number of methods you need to write. For example if you have a case for Ellipse and Point, you can inherit Circle from Ellipse and then use the existing case when comparing Circle with Point as well.

 
精彩推荐
图片推荐