在OO设计方面,可以从单一基类派生出二维和三维点类吗?

时间:2009-06-26 21:59:12

标签: graphics oop

我目前正在设计简单的图形编辑器,它支持二维和三维形状的琐碎操作。
关键是,我想像MsPaint一样渲染这些形状的原型。目前它正在呈现我需要存储画布中的某些像素,这些像素被原型覆盖,以防原型更改以在画布上恢复其状态。所以,我希望我的所有形状都支持这种缓冲(图形操作是所有渲染操作的基类):

public abstract class Shape: GraphicOperation {
        protected List<SomePoint> backup;
        public Shape(Color c): base(c) { }

        public Color FigureColor {
            get { return color; }
            protected set { color = value; }
        }
        public abstract void renderPrototype(Bitmap canvasToDrawOn);
}


主要的想法是,就OO设计而言,在基类(Shape)级别上提供缓冲区的支持会很棒,我的意思是对于TwoDShape和ThreeDShape类,这个列表必须以不同的方式初始化 - 对于具有TwoDPoint实例的TwoDShape ,以及具有ThreeDPoint实例的ThreeDShape 但要做到这一点, SomePoint必须是二维点和三维点类的基类。 从OO方面来说,从单个基类派生这两个类是否可接受?
可能有太多的话,但我只是想让每个人都明白这个问题 编辑:顺便说一句,这是从他们的形状之王派生点类的好主意吗?我个人认为没有其他选择,但如果我直接从形状中推出它可能会更好吗?现在是:

public abstract class TwoDShape : Shape {
        protected List<SomePoint> backup;
        public TwoDShape(Color c) : base(c) { }
    }
public class TwoDPoint: TwoDShape {
        //...
}

和ThreeDPoint一样。

7 个答案:

答案 0 :(得分:2)

我认为没有任何理由不这样做。但是,如果Shapes之间的唯一区别在于它们包含的Point类型,为什么不将Shape类本身作为模板,或者用Java术语中的“泛型”?

答案 1 :(得分:2)

2d和3d点有什么共同之处?如果它只是“在将它们绘制到表面上时,它们会替换应该备份的像素”,这听起来更像是合成而不是继承给我。 2d和3d形状都有一个的像素缓冲区,它们正在替换它们。

无论如何,当你想要基类时,你能总是使用2d和3d形状吗?

如果是这样,给他们一个共同的基类。否则不要。

根据对象的使用方式确定类设计。如果它们在具有公共基础的上下文中使用,则将其实现为公共基类。如果只是“我不能为两者添加数据成员而烦恼”,继承可能不是正确的工具。

答案 2 :(得分:2)

我想不出任何方式做到这一点,不会以某种微妙(或不那么微妙)的方式违反Liskov替代原则。这是一个典型的例子,说明为什么不对继承感到疯狂,因为两个类共享一些字段,例如herehere

最后,即使你让它发挥作用,它也可能对你所写的方法有很多陷阱和限制,我无法想象这将是一场净胜利。

答案 3 :(得分:1)

OOD有一个完全一般的规则,即:赞成合成而不是继承。

这在实践中意味着您不应该使用继承来重用代码。如果这样做的动机是利用多态性,那么使用继承仍然是合法且有效的。

在你的情况下,如果你能设法以这样的方式编写抽象类/接口SomePoint,你只能在那个级别上处理它,而且永远不需要向下转换,你绝对应该去做。

另一方面,如果你发现你需要将实例向下转换为TwoDPoint或ThreeDPoint,那么你从继承中得不到任何东西,你就会破坏Liskov替换原则。如果是这种情况,您应该考虑一种设计,您可以在不依赖继承的情况下实现重用 - 可能使用服务或策略。

答案 4 :(得分:0)

在游戏中,2d点和3d点通常不会相互继承,但说实话,我想不出任何根本原因。所以是的,它应该没问题,因为命名它们通常是vector2和vector3,所以它们可以保持尺寸,点和颜色,都在同一个对象中。

答案 5 :(得分:0)

难道你不能让ThreeDimensionalPoint从TwoDimensionalPoint派生出来吗?

public class ThreeDimensionalPoint : TwoDimensionalPoint
{

}

我可以在2D中看到很多可重用的代码(方法/属性)在3D中是相同的......你可能想要从2D的角度看3D,然后你需要做的就是施展它。只是我的想法...

答案 6 :(得分:0)

一个更简单的解决方案,以及一个避免一些微妙设计问题的解决方案是将所有点视为3D,如果您在2D上下文中工作,则只需忽略Z坐标。您可以将2D形状视为简单的3D形状,恰好位于平面上。