面向数据的设计中的接口

时间:2018-12-30 11:20:34

标签: interface abstraction data-oriented-design

俗话说得像这样:

“编程到接口/抽象,而不是实现”。

我们都知道接口是在面向对象编程中解耦的一种方式。就像某些对象要履行的合同。

但是我无法缠住的东西是:

在面向数据的设计中如何编程接口/抽象?

就像调用某些“ Drawable”一样,但是我现在不知道它是矩形还是圆形,但是它实现了“ Drawable”接口。

谢谢

1 个答案:

答案 0 :(得分:1)

这是一个很好的问题。我相信您要问的是如何使用面向数据的设计(DOD)实现多态?

简短答案:您不需要使用界面。这是一种实现多态的面向对象编程(OOP)的方式。在DOD中,可以通过实体组件系统(ECS)模式实现多态性。

长答案(带有示例):

这是OOP中多态的一个例子:

public interface Drawable
{
   void Draw();
}

public class Circle: Drawable
{
   public float posX, posY;
   public float radius;

   public void Draw() { /* Draw Circle */ }
}

public class Rectangle: Drawable
{
   public float posX, posY;
   public float width, height;

   public void Draw() { /* Draw Rectangle */ }
}

以下是使用DOD和ECS(伪代码)实现多态的方法:

public struct Position { public float x, y; }
public struct Circle { public float radius; }
public struct Rectangle { public float width, height; }

public class DrawCirlceSystem
{
    public void OnUpdate()
    {
        ComponentQuery
            .SelectReadOnly(typeof(Position), typeof(Circle))
            .ForEachEntity((Entity entity, Position position, Circle circle) => {
                /* Draw Circle */
            });
    }
}

public class DrawRectangleSystem
{
    public void OnUpdate()
    {
        ComponentQuery
            .SelectReadOnly(typeof(Position), typeof(Rectangle))
            .ForEachEntity((Entity entity, Position position, Rectangle rectangle) => {
                /* Draw Rectangle */
            });
    }
}

因此,如果您具有以下数据布局:

Entity 1: [Position, Circle]
Entity 2: [Position, Circle]
Entity 3: [Position, Rectangle]

DrawCircleSystem将仅在实体1和2上执行,而DrawRectangleSystem将仅在实体3上执行。因此,通过这些系统的可查询性可以实现多态。

与OOP相比,以这种方式进行编程的性能更高。但是除此之外,它还使我们的代码更具可扩展性和可优化性。例如,如果您想实施剔除,以便仅实际渲染视图内的实体,我们可以以很少的重构工作轻松地做到这一点。我们需要做的就是引入一个新系统来处理剔除,方法是在要绘制的实体中添加或删除名为Visible的新组件:

public struct Visible { }

public class CircleCullingSystem
{
    public void OnUpdate()
    {
        // Give me all Circle entities that are NOT Visible
        ComponentQuery
            .SelectReadOnly(typeof(Position), typeof(Ciricle))
            .Exclude(typeof(Visible))
            .ForEachEntity((Entity entity, Position position, Circle circle) => { 
                // Add 'Visible' component to entity if it's within view range
            });

        // Give me all Circle entities that are Visible
        ComponentQuery
            .SelectReadOnly(typeof(Position), typeof(Ciricle))
            .FilterBy(typeof(Visible))
            .ForEachEntity((Entity entity, Position position, Circle circle) => { 
                // Remove 'Visible' component from entity if it's out of view range
            });

    }
}

然后我们只更新DrawCirlceSystem中的查询,以便它按Visible组件进行过滤:

public class DrawCirlceSystem
{
    public void OnUpdate()
    {
        // Process all visible circle entities
        ComponentQuery
            .SelectReadOnly(typeof(Position), typeof(Circle))
            .FilterBy(typeof(Visible))
            .ForEachEntity((Entity entity, Position position, Circle circle) => {
                /* Draw Circle */
            });
    }
}

当然,我们需要创建一个类似于RectangleCullingSystem的{​​{1}},因为矩形的剔除行为不同于圆形。