Интерфейсы в ориентированном на данные дизайне - PullRequest
0 голосов
/ 30 декабря 2018

Поговорка звучит примерно так:

"Программирование на интерфейс / абстракцию, а не на реализацию".

Все мы знаем интерфейсы как средство развязки в объектно-ориентированном программировании.Как контракт, который выполняет какой-то объект.

Но что-то, чего я не могу обернуть, это:

Как мне программировать на интерфейс / абстракцию в ориентированном на данные дизайне?

Как и в случае вызова некоторого "Drawable", но сейчас я не знаю, прямоугольник это или круг, но он реализует интерфейс "Drawable".

Спасибо

1 Ответ

0 голосов
/ 01 февраля 2019

Это отличный вопрос.Я полагаю, что вы спрашиваете, как достичь полиморфизма с помощью Data Oriented Design (DOD)?

Краткий ответ: Вы не делаете это с интерфейсами.Это способ объектно-ориентированного программирования (ООП) для достижения полиморфизма.В DOD полиморфизм может быть достигнут с помощью шаблона Entity Component System (ECS).

Длинный ответ (с примерами):

Вот пример полиморфизма в ООП:

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. Таким образом, полиморфизм достигается за счет возможности запроса этих систем.

Программирование таким способом значительноболее производительный, чем ООП.Но помимо этого, он также делает наш код более масштабируемым и оптимизируемым.Например, если вы хотите реализовать отбор, чтобы на самом деле отображались только те объекты, которые находятся в пределах представления, мы можем легко сделать это с минимальными усилиями по рефакторингу.Все, что нам нужно сделать, это ввести новую систему, которая обрабатывает отбор, добавляя или удаляя новый компонент с именем 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, аналогичный нашему CircleCullingSystem, так как поведение отбраковки прямоугольников отличается откруги.

...