Лучший способ создать SpriteBatch при переносе базовых объектов - PullRequest
1 голос
/ 23 января 2012

Сама проблема здесь довольно проста, но все решения кажутся плохими, поэтому я не могу решить, какой из них лучше, поэтому подумал, что мне следует спросить здесь ...

В настоящее время я обертываю несколько компонентов XNA (SpriteBatch, GraphicsDevice, ContentLoader и т. Д.), По большей части они оборачивают все 1-1, но есть несколько отличий, когда необязательные аргументы сокращают перегрузку функций. Это в основном делается для того, чтобы включить Dependency Injection и позволить мне намного проще имитировать тесты, так как я предпочел бы использовать шаблон внедрения, а не шаблон локатора службы (хотя я также создал NinjectServiceProvider, который реализует IServiceProvider).

В любом случае, главная проблема здесь в том, что мне нужно обновить несколько разных объектов ISpriteBatch из-за разных компонентов, использующих разные режимы наложения и т. Д. Поэтому я создал новый объект SpriteBatchFactory. Прежде чем продолжить, приведу несколько примеров фрагментов, чтобы вы могли видеть, откуда я иду:

public class MySpriteBatch : ISpriteBatch
{
    private SpriteBatch underlyingSpriteBatch;
    private IGraphicsDevice graphicsDevice;

    public MySpriteBatch(SpriteBatch underlyingSpriteBatch, 
        IGraphicsDevice graphicsDevice)
    { 
        this.underlyingSpriteBatch = underlyingSpriteBatch; 
        this.graphicsDevice = graphicsDevice;
    }

// ...
}

MyGraphicsDevice:

public class MyGraphicsDevice : IGraphicsDevice
{
    private GraphicsDevice underlyingGraphicsDevice;

    public MyGraphicsDevice(GraphicsDevice underlyingDevice)
    {
        this.underlyingGraphicsDevice = underlyingDevice;
    }

    // ...
}

SpriteBatchFactory:

public class SpriteBatchFactory
{
    public SpriteBatchFactory(IGraphicsDevice graphicsDevice)
    {
        this.GraphicsDevice = graphicsDevice;
    }

    public IGraphicsDevice GraphicsDevice { get; private set; }

    public ISpriteBatch Create()
    {
        var underlyingGraphicsDevice = ????

        var underlyingSpriteBatch =
            new SpriteBatch(underlyingGraphicsDevice);

        return new MySpriteBatch(underlyingSpriteBatch,
            this.GraphicsDevice);
    }
}

Теперь, как вы можете видеть, чтобы создать MySpriteBatch (ISpriteBatch), мне требуется новый SpriteBatch, для которого, в свою очередь, требуется экземпляр GraphicsDevice ... и я не уверен, как лучше удовлетворить эту зависимость ... A Вот несколько решений, о которых я подумал:

1) MyGraphicsDevice содержит это, но оно не раскрывается, поэтому я могу представить его как объект на уровне интерфейса или как реальный GraphicsDevice на уровне конкретного класса. В любом случае это потребует приведения типа объекта -> GraphicsDevice или IGraphicsDevice -> MyGraphicsDevice.

2) Я даю SpriteBatchFactory GraphicsDevice, а не IGraphicsDevice и новый, каждый раз, когда мне нужно обновить MySpriteBatch.

3) Я создаю MySpriteBatch для внутреннего создания SpriteBatch, для него требуется MyGraphicsDevice и выставляю его там, поэтому MySpriteBatch не имеет внешней зависимости от SpriteBatch.

Я думаю, что третий звучит более инкапсулированным способом сделать это, но мне не нравится ни один из способов, так может кто-нибудь еще придумает более хороший способ решить эту проблему? Меня не беспокоит наличие зависимостей XNA, так как я не пытаюсь создать эту кроссплатформенность, просто пытаюсь дать мне более управляемый слой между Xna и моей структурой.

=== Редактировать ===

Когда я говорю, что я обертываю базовые компоненты, я имею в виду буквально обертку вызовов, то есть:

public class MyGraphicsDevice : IGraphicsDevice
{
    private GraphicsDevice underlyingGraphicsDevice;

    public MyGraphicsDevice(GraphicsDevice underlyingDevice)
    {
        this.underlyingGraphicsDevice = underlyingDevice;
    }

    public VertexBuffer[] GetVertexBuffers()
    {
        return underlyingGraphicsDevice.GetVertexBuffers();
    }

    public void SetRenderTarget(RenderTarget2D renderTarget)
    {
        underlyingGraphicsDevice.SetRenderTarget(renderTarget);
    }

    // ...
}

Так что на самом деле никакой пользовательской логики нет, это просто глупая оболочка.

...