Помогите со структурой абстрактного класса / класса / интерфейса Unit - PullRequest
2 голосов
/ 22 декабря 2009

Я помогаю моему другу разработать конвертер единиц измерения. Он спросил меня, могу ли я помочь разделить работу. Поэтому я делаю .dll под названием Unit. Блок должен обрабатывать преобразования. Я провел мозговой штурм о том, как это сделать, и мне пришла в голову идея поставить каждому разделу перечисление (например, enum Angle [градусы, радианы, градианы], enum Area [квадратные метры, квадратные мили, ...], enum Energy [Ньютоны, Паскали, Джоули, ...], ...). Затем основной абстрактный класс Unit со всеми методами Convert.
Примечание:
Я НЕ прошу вас закодировать .dll, я просто хочу ваше мнение о КАК , чтобы сделать .dll.

Ответы [ 3 ]

2 голосов
/ 22 декабря 2009

Когда вы имеете отношение типа «многие ко многим» (например, каждое значение хочет иметь возможность преобразовать его в любой другой тип значения в своем классе), стоит обратить внимание на то, что вы в конечном итоге напишите тонну методы, если вы используете метод грубой силы написания функции преобразования для каждой возможности.

Это нормально, если вам нужно, чтобы это работало как можно быстрее и вы хотели, чтобы ваша ошибка контролировалась, но вы страдаете из-за удобства сопровождения кода.

Что-то, что я делал в прошлом для конвертации между многими единицами, было установление «базовой» единицы, в которую можно преобразовать все, и написание функций для преобразования в / из этого. Это позволяет вам определять интерфейс примерно так:

interface IUnitConverter<T, U> {
 T ToBaseUnit();
 void FromBaseUnit(T BaseValue);
 U MyValue {get;}
}

И специализировать это для определенных типов конвертации:

class RadiansConverter : IUnitConverter<DegreesConverter, float> {
 float radians = 0;

 DegreesConverter ToBaseUnit() {...}
 void FromBaseUnit(DegreesConverter BaseValue) {...}
 float MyValue {get {return radians;}}
}

Редактировать: Использование:

// assume we have a constructor that sets the private value
float degrees = new RadiansConverter(Math.PI).ToBaseUnit().MyValue;
float radians = new RadiansConverter().FromBaseUnit(degrees).MyValue;

Это может быть несколько тяжеловесно, и вы должны следить за распространением ошибок, которые могут ударить вас по двум преобразованиям вместо одного. Это пригодилось, когда мне нужно было выполнять сложные преобразования ГИС, для которых также требовалось сохранять состояние, но это может быть не совсем то, что вы ищете.

1 голос
/ 22 декабря 2009

Я бы предпочел такой дизайн:

var measure = Angle.FromDegrees(10);
Console.Write(measure.ToRadians());

Просто с точки зрения удобства использования кода я не вижу никакого удобства в добавлении перечислений.

Это было бы похоже, например, как TimeSpan реализован в рамках.

0 голосов
/ 22 декабря 2009

Почему один .dll?

  • У вас есть n наборов конвертируемых единиц: угол, энергия, площадь, температура и т. Д.
  • В каждом наборе x возможных единиц измерения: градусы, радианы и градианы в пределах угла.

В этом наборе x единиц вы имеете (если я правильно помню свою математику) x! возможных преобразований, что не проблема, когда x = 3, но это немного сложнее для Района, где вы можете иметь квадратные миллиметры, сантиметры, метры, дюймы, футы, ярды, цепи, фарлонги или мили, а также гектары и акры, и это без поездки в Википедию на ищите что-нибудь более неясное. 11! чуть менее 40 миллионов возможных конверсий.

Я бы соблазнился сделать один .dll (или, точнее, один класс и, возможно, поместить все классы в один и тот же .dll) для каждого из n наборов конвертируемых единиц и внутри каждого. dll конвертирует все через одну стандартную единицу, так что вам не нужно запускать один или два из 2 ( x - 1) конверсий в расчете на конверсию, скажем, конвертируя все входные данные в квадратные метры, а затем снова выводя вместо кодирования до каждой возможной комбинации. Двадцать конверсий звучат гораздо быстрее, чем сорок миллионов: -)

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

Я не могу придумать хороший способ, чтобы все классы реализовали один и тот же интерфейс, потому что каждое преобразование будет принимать два параметра из перечисляемых типов (от и до), и это перечисление будет различным для каждого класса. Дженерики могут предложить более чистое решение, но я не могу понять, как именно сейчас - кто-то еще ответил, когда я печатал, но я еще не читал этот ответ.

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