面向数据设计中的接口
Interfaces in data oriented design
谚语是这样说的:
"Program to an interface/abstraction, not to an implementation".
我们都知道接口是面向对象编程中的解耦手段。就像一些对象履行的合同。
但我无法理解的是:
如何在面向数据的设计中为 interface/abstraction 编程?
就像调用一些 "Drawable" 但我现在不知道它是矩形还是圆形,但它实现了接口 "Drawable"。
谢谢
这是一个很好的问题。我相信你问的是如何用面向数据的设计(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 */
});
}
}
当然,我们需要创建一个类似于 CircleCullingSystem
的 RectangleCullingSystem
,因为矩形的剔除行为不同于圆形。
谚语是这样说的:
"Program to an interface/abstraction, not to an implementation".
我们都知道接口是面向对象编程中的解耦手段。就像一些对象履行的合同。
但我无法理解的是:
如何在面向数据的设计中为 interface/abstraction 编程?
就像调用一些 "Drawable" 但我现在不知道它是矩形还是圆形,但它实现了接口 "Drawable"。
谢谢
这是一个很好的问题。我相信你问的是如何用面向数据的设计(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 */
});
}
}
当然,我们需要创建一个类似于 CircleCullingSystem
的 RectangleCullingSystem
,因为矩形的剔除行为不同于圆形。