Я написал класс с именем Container, который обрабатывает иерархии (видимые для пользователя класса) и конвертирует их внутренне в плоский массив.Поэтому для внешней части контейнера он выглядит как иерархия контейнеров, каждый из которых имеет родительские и дочерние узлы.
Эту функцию я хочу добавить к определенным классам.Например, класс Widget, он должен иметь ту же функциональность, определенную Container.
Я мог бы позволить Widget наследовать от Container.Контейнер теперь определен как класс с this (), членом данных, функциями-членами, инвариантом и тестами модулей.Контейнер содержит массив Контейнеров, поэтому в дизайне есть одна ошибка: что если Foobar также наследует Контейнер и мы добавим элементы Foobar в контейнер Виджета?Это должно быть запрещено.Они действительно используют один и тот же базовый класс, но это принципиально разные вещи с разными целями ... просто они, кажется, разделяют некоторые функции.
Определение контейнера как интерфейса невозможно, так как он содержит элементы данных (ине решает проблему).Определить контейнер как миксин тоже нельзя, поскольку у нас тоже есть функция this () (или как это сработает?).Атрибуты видимости для функций в миксинах тоже не работают.Кроме того, я не могу передать ему аргумент this
класса Widget, так как это должен быть первый элемент плоского массива.
Я подумал о том, чтобы передать Container аргумент шаблона, сообщив ему, чтоКонтейнер имеет:
abstract class Container(T)
{
...
T[] elements;
}
class Widget: Container!Widget
{
}
Это приводит к ошибке: class container .__ unittest2.Widget базовый класс напрямую ссылается Container.
Как бы вы это реализовали?Я также мог бы добавить проверки в Контейнер, который гарантирует, что при добавлении дочернего элемента он будет иметь тот же тип, что и родительский.Но как мне это проверить?
abstract class Container
{
void add(Container child)
{
// pseudo-code
assert (is(getFirstDerivedType(this) == getFirstDerivedType(child)));
...
}
...
Container[] elements;
}
РЕДАКТИРОВАТЬ: Даже если первый фрагмент кода не сигнализирует об ошибке, он все равно не решает проблему.Я не могу произвольно добавить больше функциональности, поскольку разрешен только один базовый класс.Другие должны быть интерфейсами, которые принципиально разные вещи.Интерфейсы гарантируют, что в производном классе есть определенные функциональные возможности, они сами не добавляют функциональность.
Это должно быть решено с помощью (шаблона) миксинов.Но миксины не могут добавлять код в конструктор (только заменить, если не определен), не могут добавлять код в инвариант (определен несколько раз инвариант), не могут задавать видимость функции-члена или использовать другие ключевые слова, специфичные для класса / структуры ...