Интерфейс Publi c с разработчиками, имеющими дополнительные данные? - PullRequest
0 голосов
/ 25 апреля 2020

С интерфейсом publi c IGameTrack для реализации на самом деле требуется больше данных, чем открыто для этого интерфейса. Я придумал шаблон, который, кажется, работает, то есть явную реализацию, Array.Find и приведение, но мне было интересно, может ли быть другой подход для Game5.Install(IGameTrack):

public interface IGame
{
    [NotNull]
    [ItemNotNull]
    IReadOnlyList<IGameTrack> Tracks { get; }

    void Install([NotNull] IGameTrack track);
}

public interface IGameTrack
{
    [NotNull]
    string Name { get; } // nothing more needs to be exposed than this
}

internal sealed class GameTrack5 : IGameTrack // but custom implementation needs extra data
{
    public GameTrack5([NotNull] string name, int position)
    {
        Name = string.IsNullOrWhiteSpace(name)
            ? throw new ArgumentException("Value cannot be null or whitespace.", nameof(name))
            : name;

        Position = position < 0
            ? throw new ArgumentOutOfRangeException(nameof(position))
            : position;
    }

    public string Name { get; }

    public int Position { get; }

    string IGameTrack.Name => Name;
}

public sealed class Game5 : IGame
{
    [NotNull]
    [ItemNotNull]
    private IReadOnlyList<GameTrack5> Tracks { get; } = new[]
    {
        new GameTrack5("abcd", 1234)
    };

    IReadOnlyList<IGameTrack> IGame.Tracks => Tracks;

    public void Install(IGameTrack track) // works but is a bit weird
    {
        if (track == null)
            throw new ArgumentNullException(nameof(track));

        // TODO anything better than that ?

        if (!(Array.Find(Tracks.Cast<IGameTrack>().ToArray(), s => s == track) is GameTrack5 result))
            throw new ArgumentNullException(nameof(result));

        var name     = result.Name;
        var position = result.Position; // our extra data we'll need
    }
}

Вопрос :

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

Чтобы было ясно, IGame.Install(IGameTrack) получит IGameTrack, из которого он должен сопоставьте с его спецификацией c реализации IGameTrack, в этом случае это будет GameTrack5.

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

Возможное решение, которое не предоставляет реализации из IGameTrack:

using System;
using System.Collections.Generic;
using OpenAG.Annotations;

// ReSharper disable once CheckNamespace
namespace Whatever
{
    public interface IGame
    {
        string Name { get; }

        IReadOnlyList<IGameTrack> Tracks { get; }

        void Install([NotNull] IGameTrack track);
    }

    internal interface IGame<in T> : IGame where T : IGameTrack
    {
        void Install([NotNull] T track);
    }

    public interface IGameTrack
    {
        string Name { get; }
    }

    public class Game1 : IGame, IGame<GameTrack1>
    {
        public string Name { get; }

        public IReadOnlyList<IGameTrack> Tracks { get; }

        public void Install(IGameTrack track)
        {
            (this as IGame<GameTrack1>).Install(track as GameTrack1 ?? throw new InvalidOperationException());
        }

        void IGame<GameTrack1>.Install(GameTrack1 track)
        {
            if (track == null)
                throw new ArgumentNullException(nameof(track));

            throw new NotImplementedException();
        }
    }

    internal class GameTrack1 : IGameTrack
    {
        public string Name { get; }
    }
}

1 Ответ

0 голосов
/ 25 апреля 2020

Я нашел самое простое решение, которое может быть:

  1. определить, какая у нас версия игры
  2. перечислить все треки, которые есть в версии
  3. говорит треку установить себя
  4. это приводит к
    • не нужно громоздких дженериков, приведение
    • трек имеет доступ к своим собственным данным

Я только что придумал это, потому что мне пришлось добавить дополнительный слой, а затем, сыт по горло этой постоянно растущей и ненужной сложностью, решение появилось волшебным образом: KISS.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...