Интерфейс библиотеки DLL - PullRequest
1 голос
/ 19 июля 2009

У меня есть вопрос, который беспокоит меня долгое время.

У меня есть математическая библиотека, реализованная как DLL. Библиотека реализует множество типов математических функций. Математические функции реализованы в разных классах в зависимости от их функциональности. Например, все функции, которые реализуют полиномиальные уравнения, находятся под CPolynom, все функции, которые реализуют дифференциальные уравнения, находятся под CDifferential.

DLL должна предоставлять интерфейс. Теперь мой вопрос:

Вариант 1

Я могу реализовать в одном заголовочном файле один интерфейсный класс, который включает все «вспомогательные» методы интерфейса всех практических классов => С одной стороны, я открываю для внешнего мира только один заголовочный файл с одним классом, с другой Хотя этот класс может быть огромным, включая методы интерфейса, которые не связаны (т.е. кто-то хочет функциональность CPolynom, он / она должен будет включить огромный заголовочный файл и создать огромный класс интерфейса)

Вариант 2

Я могу реализовать интерфейсный класс для каждого класса в отдельном заголовочном файле. => С одной стороны, я делю классы на разные файлы в зависимости от функциональности. Если кому-то нужна определенная функциональность, ему / ей нужно будет включить только соответствующий файл. С другой стороны, я могу получить много заголовочных файлов, представленных во внешнем мире.

Какой подход считается более профессиональным, более правильным в дисциплине проектирования программного обеспечения?

Спасибо, David

Ответы [ 6 ]

1 голос
/ 20 июля 2009

Я обычно реализую один заголовок на класс. Если вы всегда нуждаетесь во взрыве заголовков, потому что вам нужно «один из столбца A и два из столбца B», это, как правило, подразумевает некоторый запах кода проекта. Например, у вас есть одна ответственность, распределенная по нескольким классам, а не сосредоточенная в одном классе.

0 голосов
/ 20 июля 2009

Вариант 2 будет выглядеть естественно и профессионально для всех.

Так работает большинство библиотек.

Однако группировка небольших связанных классов в одном и том же заголовке (но с несколькими заголовками для всего API) звучит очень разумно.

Самые большие недостатки, которые я вижу в варианте 1: - Все в большом классе может быть трудным для обработки: когда разработчик занят использованием CPolynom, потерять его объявление между CDifferential и другим классом будет болезненно. - Использование пространства имен больше подходит для агрегирования классов, чем для более крупного «материнского» класса.

Короче говоря, я бы выбрал вариант 2 со всеми классами в пространстве имен библиотеки.

0 голосов
/ 20 июля 2009

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

Рассматривали ли вы возможность добавления COM-интерфейса в библиотеку? Вместо отправки отдельного .h файла ваши пользователи могут просто:

#import "mathFunctions.dll" named_guids

Автоматически объявленные интеллектуальные указатели делают функции пригодными для использования без дополнительных ручных объявлений или даже очистки. Вы можете определить свою документацию в IDL, которая будет появляться во всплывающих подсказках в IDE, когда ваши клиенты будут использовать ваш код. Ваш код также можно использовать на всех языках Microsoft от VB3-6, wscript и .Net.

double myFunc(double x)
{
  double a=1, b=2, c=3, y=0;
    MathLib::PolynomPtr polynom(CLSID_CPolynom, 0, CLSCTX_INPROC_SERVER);
    y = polynom->someFunction(a, b, c, x); // use it somehow
    return y;
}

Используемый in-proc, COM добавляет только около 16 циклов накладных расходов на выполнение каждой функции. Поскольку это умный указатель, вам не нужно его чистить. И я не включил его выше, но, как и во всем внешнем, вы должны добавить базовые обертки для функций try / catch:

catch (_com_error &e) { printf("COM error: %08x %s\n", e.Error(), e.Description()) };
0 голосов
/ 19 июля 2009

Один заголовок (или несколько, если интерфейсов много, и вы можете сгруппировать их логически), но отдельные классы также возможны. Не создавайте один огромный класс с кучей методов, как вы собирались сделать в варианте 1.

0 голосов
/ 19 июля 2009

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

0 голосов
/ 19 июля 2009

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

Лично я не вижу ничего плохого в одном большом заголовке, когда я пытаюсь использовать маленькие заголовки в качестве пользователя, у меня всегда возникают проблемы типа "Мне нужна только 1 функция из заголовка X, 2 из заголовка Y, .. .. "и в конце концов, я получаю 15 включений в одну библиотеку в каждом файле * .cpp, что раздражает (поэтому я сам создаю один большой заголовок :)).

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