根据我所学到的,如果经常在类层次结构中使用向下转换,那就不好了。
我同意这一点,但是如果有的话,这个规则的例外情况是什么?
这就是我的图形编辑器设计显得很薄的地方:我有两个层次结构,其中几何图形层次结构与图形基元分离。像这样:
public class GeometricPrimitive {...}
public class RectangeGeometric: Geometric Primitive {...}
public class GraphicPrimitive {...}
public class Rectangle: GraphicPrimitive {
private RectangleGeometric figure;
...
}
因此,每个具体的图形图类都封装了具体几何类的实例。
这种方法是正确的,还是我更喜欢更通用的? - 不幸的是,向下转换将是在这种情况下使用:
public class GraphicPrimitive {
protected GeometryPrimitive figure;
....
}
public class Rectangle: GraohicPrimitive {
public Rectangle(Color c, TwoDPoint leftHighPoint, TwoDPoint rightLowPoint):
base(new RectangleGeometric(leftHighPoint.Point2D, rightLowPoint.Point2D), c) { }
#region Geometric Properties
public TwoDPoint LeftTopCorner {
get { return new TwoDPoint(base.color, (base.figure as RectangleGeometric).LeftTopCorner); }
}
public TwoDPoint RightBottomCorner {
get { return new TwoDPoint(base.color, (base.figure as RectangleGeometric).RightBottomCorner); }
}
答案 0 :(得分:4)
虽然你的问题缺乏关于你的应用程序的一些更大的背景,这将有助于给出一个特定的答案,但我会尝试给你一些关于如何使用你的代码实现灵感的想法。
我将从反转GeometryPrimitive和GraphicPrimitive的关系开始。我将GeometryPrimitive层次结构视为构成抽象场景图的域对象,将GraphicPrimitive层次结构视为低级视图组件,将GeometryPrimitive转换为适合绘制到某种图形上下文的一组像素。 GeometryPrimitive子类包含描述自身所需的所有状态信息,但没有将该描述转换为像素的逻辑。 GraphicPrimitive子类具有所有像素推送逻辑,但没有内部状态。实际上,GraphicPrimitive层次结构表示Command Objects的层次结构。
在GeometryPrimitive基类中,包含一个名为GetGraphicPrimitive()的抽象方法。在GraphicPrimitive基类中包含一个名为Draw(Graphics g)的抽象方法。
在每个GeometryPrimitive中,包括用于绘制对象的相应GraphicPrimitive和用于访问它的访问器方法。要绘制整个场景,请遍历GeometryPrimitive对象的结构,询问每个对象的GraphicPrimitive,然后调用Draw()方法。
abstract class GeometryPrimitive
{
public abstract GraphicsPrimitive GetGraphicsPrimitive();
}
abstract class GraphicsPrimitive
{
public abstract void Draw(Graphics g);
}
class RectangleGeometryPrimitive : GeometryPrimitive
{
public Point TopLeft {get; set;}
public Point BottomRight {get; set;}
private RectangleGraphicPrimitive gp;
public RectanglePrimitive(Point topLeft, Point bottomRight);
{
this.TopLeft = topLeft;
this.BottomRight = bottomRight;
this.gp = new RectangleGraphicsPrimitive(this);
}
public GraphicsPrimitive GetGraphicsPrimitive()
{
return gp;
}
}
class RectangleGraphicsPrimitive : GraphicsPrimitive
{
private RectangleGeometryPrimitive p;
public RectangleGraphicsPrimitive(RectangleGeometryPrimitive p)
{
this.p = p;
}
public void Draw(Graphics g)
{
g.DrawRectangle(p.TopLeft, p.BottomRight);
}
}
class CircleGeometryPrimitive : GeometryPrimitive
{
public Point Center {get; set;}
public int Radius {get; set;}
private CircleGraphicPrimitive gp;
public RectanglePrimitive(Point center, int radius);
{
this.Center = center;
this.Radius = radius;
this.gp = new CircleGraphicsPrimitive(this);
}
public GraphicsPrimitive GetGraphicsPrimitive()
{
return gp;
}
}
class CircleGraphicsPrimitive : GraphicsPrimitive
{
private CircleGeometryPrimitive p;
public CircleGraphicsPrimitive(CircleGeometryPrimitive p)
{
this.p = p;
}
public void Draw(Graphics g)
{
g.DrawCircle(p.Center, p.Radius);
}
}
正如您在上面所看到的,不需要向下转换就可以将GeometryPrimitives绘制到屏幕上。通过正确使用继承,您还可以在不同的GeometryPrimitive之间共享GraphicsPrimitive对象。例如,如果SquareGeometryPrimitive派生自RectangleGeometryPrimitive,则SquareGeometryPrimitive和RectangleGeometryPrimitive都可以使用RectangleGraphicsPrimitive。
答案 1 :(得分:2)
你没有提供很多细节,所以我无法真正表达我对这两个等级是否足够的看法。我们都知道这种并行性的成本,但只有你能评估它们的优势......
我不懂你的编程语言。但是,避免你提到的向下转换的一个常见解决方案是使用参数化类型(称为泛型或模板)来建立基类。这适用于Java,C ++和许多现代语言。
我们的想法是,字段base.figure
的精确类型由每个子类决定。您在基类中知道的是它是GeometryPrimitive
的子类型T.在每个子类中,您定义了替换T的精确类型RectangleGeometric
,因此在此子类中,类型是精确的。
Java示例:
public GraphicPrimitive<T extends GeometryPrimitive> {
protected T figure;
}
public Rectangle extends GraohicPrimitive<RectangleGeometric> {
// It appears in this class that the field was defined as
//protected RectangleGeometric figure;
public TwoDPoint getLeftTopCorner {
return new TwoDPoint(base.color, figure.LeftTopCorner);
}
}