Ковариантность и прочее

Общие вопросы о Unity3D

Ковариантность и прочее

Сообщение alt3d 05 окт 2018, 12:28

Навеяно этой темой: viewtopic.php?f=5&t=48615

Вот я делаю некий код для работы с кривыми.
Кривые могут быть разные - простые ломаные линии, квадратичные, кубические и т.д.
Хочу работать с ними единым образом, через интерфейсы точки и сегмента.
Но при этом хранить в сплайнах конкретные классы точек, чтобы обрабатывать их по разному.
Например поиск касательной к сплайну в случае простой линии на порядки проще и быстрее чем в сплайнах безье

Cобственно вопрос - можно-ли как-то обойтись без преобразований каждый раз интерфейса к конкретному классу и обратно?
Я тут начал читать про перезагрузку операторов преобразования: https://docs.microsoft.com/ru-ru/dotnet ... s/implicit
Но там вроде нельзя преобразовывать к интерфейсам.
Затем про ковариантность и контравариантность обобщенных интерфейсов: https://metanit.com/sharp/tutorial/3.27.php
И что-то прям вконец запутался )

То что я хочу вообще возможно?
Или это в принципе ошибочная архитектура и все такое?

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

Синтаксис:
Используется csharp

// Интерфейс точки
public interface IPoint
{
        public Vector3 Position { get; set; }            // Позиция
        public Vector3 InHandle { get; set; }          // Входная направляющая
        public Vector3 OutHandle { get; set; }       // Выходная направляющая
}

// Интерфейс сплайна
public interface ISpline
{
        IEnumerable<IPoint> GetAllPoints();                         // Получить все точки        
        void AddPoints(IEnumerable<IPoint> points);            // Добавить точек
        void RemovePoints(IEnumerable<IPoint> points);      // Удалить точек
}

// ====================================
// Кривые безье

// Точка Безье
public class LinePoint : IPoint
{
        public Vector3 Position { get; set; }
        public Vector3 InHandle { get; set; }
        public Vector3 OutHandle { get; set; }
}

// Кривая Безье
public class BezierSpline : ISpline
{
        // Список точек безье
        private readonly List<BezierPoint> Points = new List<BezierPoint>();

        public IEnumerable<IPoint> GetAllPoints()
        {
            return Points; // Естественно не компилируется
            return Points as IEnumerable<IPoint>; // Все хорошо
        }

        public void AddPoints(IEnumerable<IPoint> points)
        {
            // Работает, но нужно кастить
            Points.AddRange(points as IEnumerable<BezierPoint>);
        }

        public void RemovePoints(IEnumerable<IPoint> points)
        {
            foreach (var point in points)
            {
                // Опять дурацкое преобразование к конкретному виду
                Points.Remove(point as BezierPoint);
            }
        }
}


// ====================================
// Аналогичные классы для простой линии

// Точка линии
public class LinePoint : IPoint
{
       // ...
}

// Сплайн линии
public class LineSpline : ISpline
{
        // Список точек линии
        private readonly List<LinePoint> Points = new List<LinePoint>();
       
        // Аналогично классу BezierSpline
        // ...
}

 
alt3d
Старожил
 
Сообщения: 687
Зарегистрирован: 04 сен 2011, 21:19
  • Сайт
  • ICQ

Re: Ковариантность и прочее

Сообщение IDoNotExist 05 окт 2018, 13:32

alt3d писал(а):Cобственно вопрос - можно-ли как-то обойтись без преобразований каждый раз интерфейса к конкретному классу и обратно?

Каждый раз -это когда конкретно и для какой цели?

А вообще по моему вы сильно много сущностей поналепили в коде, интерфейсы там не нужны, да и вообще они используются в достаточно узком круге задач. ИМХО архитектура кода должна быть максимально простой и понятной, соответственно и думать стоит в сторону упрощения, если у вас архитектура кода на столько усложняется из-за нежелательного преобразования к конкретному классу, один раз за один пользовательский ввод, то по ему это того не стоит.
Аватара пользователя
IDoNotExist
Адепт
 
Сообщения: 1432
Зарегистрирован: 23 мар 2011, 09:18
Skype: iamnoexist

Re: Ковариантность и прочее

Сообщение lawson 06 окт 2018, 21:17

вариативность, астанавитесь! :-t вы действительно слишком увлеклись, у вас так вообще крыша поедет.

Я конечно слабо разбираюсь в геометрии, но вроде не много смыслю в ООП.

Целый интерфейс точки, зачем? - точка это объект с данными, она не должна обрабатывать себя сама, это должен уже делать класс ее хранящий. Я бы вообще точку запихнул в структуру если там всего три свойства в ней.
Классы BezierSpline и LineSpline я бы объединил в один который хранит, добавляет и удаляет точки - следовательно отказываемся от лишнего интерфейса ISpline, потом добавил бы просто перегрузочные методы для конкретной работы с каждым видом точки в кривой ну или вообще в базовом классе просто привел бы список точек и методы к типу Т, чтобы применить минимальные изменения в вашей архитектуре и сохранить привязку к IPoint.

Синтаксис:
Используется csharp
public abstract class Spline<T> : IEnumerable<T> where T : IPoint {
 
 private readonly List<T> points;//Кстати а зачем readonly?

 //Далее методы...
 
}

public class LineSpline : Spline<LinePoint>/*Хотя опять же, зачем для каждой точки свой класс?*/ {

 //Обрабатываем кривую с конкретными точками LinePoint

}
 
lawson
UNIверсал
 
Сообщения: 481
Зарегистрирован: 14 сен 2012, 21:20

Re: Ковариантность и прочее

Сообщение alt3d 08 окт 2018, 09:44

Ну я честно говоря, не вижу переусложнения.
Всего по паре интерфейсов и классов.

Плюс конкретно в юнити, допустим я бы хотел, чтобы сплайнами могли быть и обычные классы, и монобихейверы и скриптаблобжекты.
Их невозможно отнаследовать от одного класса, и единственный способ как-то работать с ними со всеми единым образом - интерфейсы.

Но возможно вы правы, и интерфейс точки, как минимум, здесь лишний.
Хотя вопрос был больше академический - просто интересно как делаются эти преобразования, и насколько применимы в реальной разработке.

Ну а вообще - хочу сделать генератор дорожной сети - дороги, перекрестки, столбы, светофоры, мосты, заборы и т.д.
alt3d
Старожил
 
Сообщения: 687
Зарегистрирован: 04 сен 2011, 21:19
  • Сайт
  • ICQ

Re: Ковариантность и прочее

Сообщение Cr0c 09 окт 2018, 18:53

Зачем городить под обычную линию отдельную логику, когда это - частный случай бикубической (безье из набора таких и создаются), просто вход второй противоположно направленный выход первой точки. Достаточно набора бикубических и методы для работы с набором. А уже остальное - это дело других классов: рисовать дорогу/тропинку/жд пути. Или двигать по кривой объекты.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 3035
Зарегистрирован: 19 июн 2015, 13:50
Skype: cr0c81


Вернуться в Общие вопросы

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11