LINUX.ORG.RU

Организация классов

 


0

1

Были два класса

CSerial; //базовая работа с COM портом и все константы
CSerialEx : CSerial; //мониторит порт в отдельном потоке
Потом копипастом добавилось еще два, отличающиеся только одной вложенной структурой (внутри базового) и вызывающие другой API (D2XX вместо виртуального COM порта, отличается грубо говоря префиксом в именах функций и использованием той самой структуры)
CFTSerial; //базовая работа с COM портом через D2XX и все константы
CFTSerialEx : CFTSerial; //мониторит порт в отдельном потоке
Вопрос, как организовать это и минимизировать копипаст?



Последнее исправление: Uter (всего исправлений: 1)

Обобщить код, вызывающий API, с помощью макросов

annulen ★★★★★
()
Ответ на: комментарий от yoghurt

Вообще тут ещё надо подумать, стоит ли проблема того, и не скатываться в овердизайн.

yoghurt ★★★★★
()

Макросы - зло

А вот дальше, не могу выбрать

Шаблоны или обвесить вызовы API if'ами и передавать флаг в функцию открытия порта (или просто несколько их)?

Uter
() автор топика
Ответ на: комментарий от Uter

Для вызовов конкретного API используй стратегию, которая может быть шаблонным аргументом, например.

yoghurt ★★★★★
()

добавилось еще два, отличающиеся только одной вложенной структурой (внутри базового) и вызывающие другой API (D2XX вместо виртуального COM порта, отличается грубо говоря префиксом в именах функций и использованием той самой структуры)

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

А ещё меня терзает смутное подозрение, что у первых двух классов (судя по комментариям к их объявлению) вероятно, должно было быть не наследование, а включение. Т.е. в потомке у тебя получается не разновидность предка, а класс, который «делает, что-то ещё», опираясь на методы предка.

Если моя догадка верна, то вполне возможно, что вместо CSerialEx и CFTSerialEx можно сделать один класс, а вот в качестве низкоуровневой прослойки ему можно передавать абстрактный класс работы с портом, у которого есть два потомка-реализации. Классов по-прежнему 4, но копипасты в них будет минимум

Собственно говоря, это очень похоже на диаграмму классов в вики-статье про паттерн «Стратегия» :) Да по сути, это она и есть... Хотя вру, для классической «стратегии» из статьи классов понадобится уже 5.

Хотя если CSerialEx и CFTSerialEx в низкоуровневой части не полностью полагаются на предков, а добавляют ещё какие-то вызовы API, это не спасёт.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 2)
Ответ на: комментарий от hobbit

Нет, это не включение, Ex версии не только опираются на базовый класс но и вызывают API по-другому

Uter
() автор топика
Ответ на: комментарий от Uter

но и вызывают API по-другому

Тоды ой. Но тогда и разделение между базовым классом и потомком выглядит искусственным.

Может, всё-таки подумать над тем, нельзя ли сделать так, чтобы всё API ушло в один класс? Если класс очень большой - это не проблема, проблема, когда его границы очерчены неправильно...

hobbit ★★★★★
()

Ман композиция. Какого фига вообще «мониторит порт в отдельном потоке» унаследовано от «базовая работа с COM портом и все константы»? Сделай несколько специализаций от абстрактного CSerial, а в CSerialEx передавай инстанцию одной из них.

arturpub ★★
()

CSerial и CFTSerial унаследуй от общего предка SomeSerial

вместо двух *Ex запили SerialThread(SomeSerial*)

если у них внешний интерфейс более-менее общий

MyTrooName ★★★★★
()

александреску, 2-я (вроде) глава, которая про policy. это о том, как избегать таких комбинаторных взрывов.

anonymous
()
Ответ на: комментарий от Miguel

ну, не совсем. там можно проверять типизацию и с ними работать проще. а с макросами надо работать аккуратнее.

Iron_Bug ★★★★★
()
Ответ на: комментарий от hobbit

да, я поддержу вариант с выносом API по работе с разными интерфейсами (D2XX и Virtual COM) в отдельные классы, которые будут унаследованы от абстрактного класса, представляющего девайс с необходимыми интерфейсами.
а в классы-обработчики передавать инстанс нужной реализации. можно это сделать в фабрике.
P.S. раньше много писали подобных утилек для работы с FTDI чипами, именно так и делали.

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

ну, не совсем.

Совсем, совсем.

там можно проверять типизацию и с ними работать проще.

Да, но главное — что их семантика определяется не в терминах производимых действий, а в терминах генерируемого кода.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

компилятор проверяет много вещей в темплейтах. и там при желании можно сделать много проверок. а в макросах он ничего не проверяет, просто подставляет текст.

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

компилятор проверяет много вещей в темплейтах.

Ты споришь с лиспером, а они любят приравнивать эти вещи. Хотя темплейты, сишные макросы и «нормальные макросы» - три разные сущности, хотя и могут делать похожие вещи.

DarkEld3r ★★★★★
()

+ man traits #если хочешь в компайлтайме

pon4ik ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.