Определите, какую функцию использовать в соответствии с двумя параметрами с бесконечностью комбинаций в C# - PullRequest
1 голос
/ 21 апреля 2020

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

1 / У меня есть перечисление, ссылающееся на набор системы (EPSG):

public enum System
{
    NAD27 = 3800,
    NAD83 = 3801,
    ...
    WGS84 = 4326
}

Это перечисление позволяет определить систему использования объектом Координата.

public struct Coordinate
{
    public System system;

    public double X;
    public double Y;
    public double Z;
}

Может существовать бесконечность систем. Индексы перечисления не обязательно следуют друг за другом и не должны изменяться.

2 / Необходимо, чтобы объекты могли переходить из одной системы в другую. Я применяю преобразования из одной системы в другую. Система A -> Система B. Это преобразование не меняет тип. Он изменяет значения координат (x, y и z), так что точка находится в нужном месте в зависимости от ее системы.

Возможны все комбинации. Однако, в зависимости от начальной системы, расчеты для смены систем не всегда одинаковы.

3 / У меня есть несколько классов stati c, содержащих методы преобразования:

public static class WGS84
{
    public static Coordinate ToNAD27 (double X, double Y, double Z)
    {
        ...
    }

    public static Coordinate ToNAD83 (double X, double Y, double Z)
    {
        ...
    }
}

Мы Приходите к проблеме.

4 / Чтобы определить, какое преобразование использовалось, и чтобы избежать множества случаев, когда я впервые использовал переключатель, принимающий в качестве аргумента объект, содержащий исходную систему и прибывающую систему:

public class SystemTransform
{
    public System initial;
    public System terminal;
}


public struct Coordinate 
{
    public System system;

    public double X;
    public double Y;
    public double Z;


    public Coordinate Transform (SystemTransform s)
    {
        switch(s)
        {
            case SystemTransform st when st.Initial == System.WGS84 && st.Terminal == System.NAD27:
                        return WGS84.ToNAD27(X, Y, Z);

            ...

            case SystemTransform st when st.Initial == System.WGS84 && st.Terminal == System.Z:
                        throw new NotImplementedException ($ "{s} not implmented");
        }
    }
}

5 / Будучи непрактичным и эстетичным c, я обратился к словарю:

public static class TransformWithDictionary
{
        private static Dictionary <SystemTransform, Func <Coordinate , Coordinate >> ParserMap = new Dictionary <SystemTransform, Func <Coordinate , Coordinate >>
        {
            {new SystemTransform (System.WGS84, System.NAD27), coord => WGS84.ToNAD27(coord)},
            {new SystemTransform (System.WGS84, System.NAD83), coord => WGS84.ToNAD83(coord)},
        };

        public MyObject GetParserFor (SystemTransform st, Coordinate coord)
        {
            if (! ParserMap.ContainsKey(st))
                throw new NotImplementedException ("Unexpected file type value" + st);

            return ParserMap[st](coord);
        }
}

Это немного класснее, но это не решает проблему.

В теории я сталкиваюсь с переключателем с возможностью ∞. Достаточно сказать, что невозможно заполнить его вручную и поддерживать в течение долгого времени.

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

Есть ли у вас идея шаблона проектирования для решения этой проблемы?

1 Ответ

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

Я не уверен, что полностью понимаю ваше требование, но мне кажется, что достаточно простой абстракции.

    public abstract class CoordinateSystem
    {
        public double X {get; private set; }
        public double Y {get; private set; }
        public double Z {get; private set; }

        protected CoordinateSystem( Double x, Double y, Double z )
        {
            X = x;
            Y = y;
            Z = z;
        }

        public abstract CoordinateSystemA ToA();
        public abstract CoordinateSystemB ToB();
        public abstract CoordinateSystemC ToC();
    }

    public class CoordinateSystemA : CoordinateSystem
    {
        public CoordinateSystemA( Double x, Double y, Double z )
          : base(x, y, z )
        {}

        public override CoordinateSystemA ToA() {
            return new CoordinateSystemA(X,Y,Z);
        }
        public override CoordinateSystemB ToB() {
            return new CoordinateSystemB(2,2,2);
        }
        public override CoordinateSystemC ToC() {
            return new CoordinateSystemC(3,3,3);
        }
    }

    public class CoordinateSystemB : CoordinateSystem
    {
        public CoordinateSystemB( Double x, Double y, Double z )
          : base(x, y, z )
        {}

        public override CoordinateSystemA ToA() {
            return new CoordinateSystemA(1,1,1);
        }
        public override CoordinateSystemB ToB() {
            return new CoordinateSystemB(X,Y,Z);
        }
        public override CoordinateSystemC ToC() {
            return new CoordinateSystemC(3,3,3);
        }
    }

    public class CoordinateSystemC : CoordinateSystem
    {
        public CoordinateSystemC( Double x, Double y, Double z )
          : base(x, y, z )
        {}

        public override CoordinateSystemA ToA() {
            return new CoordinateSystemA(1,1,1);
        }
        public override CoordinateSystemB ToB() {
            return new CoordinateSystemB(2,2,2);
        }
        public override CoordinateSystemC ToC() {
            return new CoordinateSystemC(X,Y,Z);
        }
    }


    public static class Program {
        public static void Main() {
            CoordinateSystem coordinateSystem = new CoordinateSystemA(1,1,1);
            CoordinateSystem b = coordinateSystem.ToB();
            CoordinateSystem c = b.ToC();
        }
    }

Помещая ToX(); в абстрактный класс, он вызывает все, наследует, координирует системы (классы) для реализации преобразования. Затем вы можете использовать абстрактный класс по всей вашей системе, не зная системы, и легко конвертировать в нужную вам систему.

Если это не соответствует вашим требованиям, я думаю, вам следует взглянуть на Шаблон посетителя. Это немного сложнее, но есть много примеров.

...