Наша область знаний включает людей, которые ходят по пластине для записи давления босыми ногами. Мы выполняем распознавание изображений, в результате чего получаются объекты класса «Foot», если в данных датчика распознается нога человека.
Есть несколько расчетов, которые должны быть выполнены на данных ноги.
Теперь, какой API будет лучше:
class Foot : public RecognizedObject {
MaxPressureFrame getMaxPressureFrame();
FootAxis getFootAxis();
AnatomicalZones getAnatomicalZones();
// + similar getters for other calculations
// ...
}
Или:
class Foot : public RecognizedObject {
virtual CalculationBase getCalculation(QString aName);
// ...
}
Сейчас есть много плюсов и минусов, которые я могу придумать, но я не могу решить, какие из них наиболее важные. Обратите внимание, что это приложение для конечного пользователя, а не библиотека программного обеспечения, которую мы продаем.
Любой совет?
Некоторые про за первый подход могут быть:
- ПОЦЕЛУЙ - все очень конкретно. API, но реализация также.
- строго типизированные возвращаемые значения.
- наследование от этого класса является надежным. Ничто не может быть переопределено, только добавлено.
- API очень закрыт, ничего не входит, ничто не может быть переопределено, поэтому меньше может пойти не так.
Некоторые минусы:
- Количество получателей будет расти, так как каждый новый расчет добавляется в список
- API, скорее всего, изменится, и если будут внесены критические изменения, нам понадобится новая версия API, Foot2.
- в случае повторного использования класса в других проектах нам может не потребоваться каждый расчет
Некоторые плюсы для второго подхода:
- более гибкий
- API менее вероятно изменится (при условии, что мы получили правильную абстракцию, в противном случае изменение будет стоить дороже)
Некоторые минусы:
- слабо набранный. Необходимо использовать каждый звонок.
- строковый параметр - у меня плохое предчувствие (ветвление строковых значений ...)
- В настоящее время не существует варианта использования / требования, которое требовало бы дополнительной гибкости, но это может произойти в будущем.
- API накладывает ограничения: каждый расчет должен быть производным от базового класса. Этот метод будет вынужден выполнять вычисления, и передача дополнительных параметров будет невозможна, если мы не разработаем еще более динамичный, сверхгибкий способ передачи параметров, который еще больше увеличивает сложность.
enum
и включить его значения. Тем не менее, я думаю, что второй вариант злой, потому что он отклоняется от KISS.getCalculation()
.Ответы:
Я думаю, что в первом подходе окупится. Волшебные строки могут создавать следующие проблемы: ошибки ввода, неправильное использование, нетривиальная безопасность возвращаемого типа, отсутствие завершения кода, неясный код (была ли эта версия в этой функции? Я думаю, мы узнаем об этом во время выполнения). Использование enums решит некоторые из этих проблем, но давайте посмотрим на минусы, которые вы подняли:
Правда, это может раздражать, однако, это делает вещи красивыми и строгими, и дает вам завершение кода в любом месте вашего проекта в любой современной IDE, с хорошими заголовочными комментариями, которые гораздо более полезны, чем перечисления.
Да, но на самом деле это огромный профессионал;) вы можете определить интерфейсы для частичных API, и тогда вам не нужно перекомпилировать зависимый класс, на который не влияют более новые API (поэтому нет необходимости в Foot2). Это обеспечивает лучшую развязку, теперь зависимость от интерфейса, а не от реализации. Более того, если существующий интерфейс изменится, у вас будет ошибка компиляции в зависимых классах, что отлично подходит для предотвращения устаревания кода.
Я не понимаю, как использование магических строк или перечислений поможет в этом ... Если я правильно понимаю, либо вы включаете код в класс Foot, либо разбиваете его на несколько меньших классов, и это касается обоих вариантов.
источник
IEnumerable<T>.Count
], такой подход может позволить коду воспользоваться преимуществами производительности новых особенности интерфейса при использовании реализаций, которые поддерживают их, но остаются совместимыми со старыми реализациями.Я бы порекомендовал вариант 3: дать понять, что вычисления не являются неотъемлемой частью абстракции a
Foot
, а работают с ней. Затем вы можете разделитьFoot
вычисления и на отдельные классы, например так:Таким образом, вы по-прежнему строго печатаете свои расчеты и можете добавлять новые, не влияя на существующий код (если только вы не допустили серьезную ошибку в объеме информации, предоставленной
Foot
).источник