Универсальные интерфейсы с абстрактными реализациями

1

Я пытаюсь реализовать некоторые алгоритмы поиска графов в.NET для развлечения и личного обучения. Для моей реализации я решил начать с класса Node, который реализовал следующий интерфейс:

public interface INode<T>
{
    T Data { get; }

    IDictionary<INode<T>, int> Neighbors { get; set; }
}

Узел содержит некоторые Data типа T, а также словарь узлов, в котором он разделяет ребро вместе с их целым расстоянием. Затем я подумал, что могу создать абстрактный класс Node:

public abstract class Node<T> : INode<T>
{
    public T Data { get; private set; }

    public IDictionary<INode<T>, int> Neighbors { get; private set; }

    public Node(T data, IDictionary<Node<T>, int> neighbors)
    {
        this.Data = data;

        this.Neighbors = neighbors;
    }
}

Вышеприведенное не работает, однако, поскольку neighbors не соответствуют Neighbors. Я хотел бы, чтобы любые параметры в конструкторе Node включали IDictionary этого конкретного типа Node а не только то, что реализует INode. Например, я могу позже создать конкретный класс под названием GraphNode, и я хочу быть уверенным, что в конструкторе используются только GraphNodes.

Чтобы решить эту проблему, я мог просто вывести IDictionary Neighbors из INode и поместить ее в абстрактный класс Node. Это может ограничить мою способность тестировать класс позже, хотя с использованием фреймворка, такого как FakeItEasy, и я не уверен, какие другие последствия он мог бы иметь на линии.

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

Теги:
design-patterns
inheritance
graph

1 ответ

2

На основе данного кода есть две вещи, которые вы можете сделать, чтобы сделать эту компиляцию.

Во-первых, код также не компилируется, потому что INode<T> не полностью реализован. Ваш интерфейс определяет метод set для Neighbors, поэтому ваш set должен быть общедоступным или вам придется явно реализовать это свойство.

Во-вторых, предположим, что вы действительно хотите ограничить свой конструктор, чтобы neighbors в качестве словаря, который был введен в класс Node<T>, а не интерфейс, самую быструю вещь, которую вы можете сделать, чтобы загрузить это. this.Neighbors меняют линию на

this.Neighbors = neighbors.ToDictionary(
    neighborDistance => (INode<T>)neighborDistance.Key,
    neighborDistance => neighborDistance.Value
);

Что-то вроде этого должно быть сделано, потому что общий IDictionary не является ковариантным.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню