在班级等级制度中经常下垂是永远邪恶的吗? [英] Is frequent downcasting in class hierarchy always evil?

查看:69
本文介绍了在班级等级制度中经常下垂是永远邪恶的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我了解,如果您经常在类层次结构中使用向下转换,那就不好了. 我同意这一点,但是该规则有什么例外情况?
这就是我的图形编辑器设计的薄弱之处:我有两个层次结构,其中几何图形层次结构与图形基元分离.像这样:

From what I`ve learned, it is no good if you frequently use downcasting in class hierarchies. I agree with that, but what are exceptions from this rule if any?
This is where my design of graphical editor shows thin: I have two hierarchies, where geometric figures hierarchy decoupled from graphic primitives one. Like this:

public class GeometricPrimitive {...}
public class RectangeGeometric: Geometric Primitive {...} 
public class GraphicPrimitive {...}
public class Rectangle: GraphicPrimitive {
 private RectangleGeometric figure;
 ...
}

因此,每个具体的图形图形类都封装了具体的几何图形类的实例.
这种方法是正确的方法,还是我应该选择更通用的方法?-不幸的是,将使用向下转换在这种情况下:

So, every concrete graphic figure class encapsulates instance of concrete geometry class.
Is that approach is the right one, or should I prefer more generical one? - unfortunately, downcasting would be used in this case:

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); }
        }

推荐答案

尽管您的问题缺少有关应用程序的较大上下文,这些上下文有助于提供特定的答案,但我将尝试通过一些思路告诉我会使用您的代码来实现这一点.

While your question lacks some of the larger context about your application that would help with giving a specific answer, I'll try by giving you some ideas of how I would implement this using your code for inspiration.

我将从反转GeometryPrimitive和GraphicPrimitive关系开始.我将GeometryPrimitive层次结构视为构成抽象场景图的域对象,并将GraphicPrimitive层次结构视为低级视图组件,这些低层视图组件将GeometryPrimitive转换为适合绘制到某种图形上下文上的一组像素. GeometryPrimitive子类保存描述自身所需的所有状态信息,但不包含将该描述转换为像素的逻辑. GraphicPrimitive子类具有所有像素推送逻辑,但没有内部状态.实际上,GraphicPrimitive层次结构表示命令对象的层次结构.

I would start by inverting the relationship GeometryPrimitive and GraphicPrimitive. I see the the GeometryPrimitive hierarchy as the domain objects that make up your abstract scene graph and the GraphicPrimitive hierarchy as low level view components that translate a GeometryPrimitive into a set of pixels appropriate for drawing onto some kind of graphics context. The GeometryPrimitive subclasses hold all the state information necessary to describe themselves but no logic for translating that description into pixels. The GraphicPrimitive subclasses have all the pixel pushing logic, but no internal state. In effect, the GraphicPrimitive hierarchy represents a hierarchy of Command Objects.

在GeometryPrimitive基类中,包含一个名为GetGraphicPrimitive()的抽象方法.在GraphicPrimitive基类中,包含一个称为Draw(Graphics g)的抽象方法.

In the GeometryPrimitive base class, include an abstract method called GetGraphicPrimitive(). In the GraphicPrimitive base class include an abstract method called Draw(Graphics g).

在每个GeometryPrimitive中,包括用于绘制对象的相应GraphicPrimitive和用于访问该对象的访问器方法.要绘制整个场景,请遍历您的GeometryPrimitive对象的结构,向每个对象询问其GraphicPrimitive,然后调用Draw()方法.

Within each GeometryPrimitive, include the appropriate GraphicPrimitive for drawing the object and an accessor method for accessing it. To draw the entire scene, walk your structure of GeometryPrimitive objects, asking each one for its GraphicPrimitive and then invoking the Draw() method.

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.

As you can see above, no downcasting is required to draw GeometryPrimitives to the screen. With proper use of inheritance, you can also share GraphicsPrimitive objects between different GeometryPrimitives. For example, SquareGeometryPrimitive and RectangleGeometryPrimitive can both use RectangleGraphicsPrimitive if SquareGeometryPrimitive derives from RectangleGeometryPrimitive.

这篇关于在班级等级制度中经常下垂是永远邪恶的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆