根据我所学到的,如果经常在类层次结构中使用向下转换,那就不好了.我同意这一点,但是如果有的话,这个规则有什么例外?
这就是我的图形编辑器设计显得很薄的地方:我有两个层次结构,其中几何图形层次结构与图形基元分离.像这样:
public class GeometricPrimitive {...}
public class RectangeGeometric: Geometric Primitive {...}
public class GraphicPrimitive {...}
public class Rectangle: GraphicPrimitive {
private RectangleGeometric figure;
...
}
Run Code Online (Sandbox Code Playgroud)
因此,每个具体的图形图类都封装了具体几何类的实例.
这种方法是正确的,还是我更喜欢更通用的方法? - 不幸的是,在这种情况下会使用向下转换:
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); }
}
Run Code Online (Sandbox Code Playgroud)
虽然您的问题缺乏有关您的应用程序的一些更大的上下文,这将有助于给出具体的答案,但我将尝试为您提供一些关于如何使用您的代码来实现这一点的想法以获得灵感。
我首先会反转 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);
}
}
Run Code Online (Sandbox Code Playgroud)
正如您在上面所看到的,将 GeometryPrimitives 绘制到屏幕上不需要向下转换。通过正确使用继承,您还可以在不同的 GeometryPrimitive 之间共享 GraphicsPrimitive 对象。例如,如果 SquareGeometryPrimitive 派生自 RectangleGeometryPrimitive,则 SquareGeometryPrimitive 和 RectangleGeometryPrimitive 都可以使用 RectangleGraphicsPrimitive。