2010-09-23 2 views
3

Большая часть моего приложения на C++ использует классы для описания модели данных, например. что-то вроде ClassType (который фактически эмулирует отражение на простом C++).Сохранение независимых модулей при использовании друг друга

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

До сих пор у меня есть следующие альтернативы:

  • Не делая его независимым и ввести зависимость от ClassType, с риском создания более «spaghetti'-зависимостей в моем приложении (это мой наименее предпочтительным раствор)
  • Представьте новый класс, например IType, и пусть мой модуль зависит только от IType. ClassType должен затем наследоваться от IType.
  • Используйте строки как метод идентификации и вынуждайте пользователей нового модуля преобразовывать ClassType в строку или наоборот, если необходимо.
  • Использование GUID (или даже простые целые числа), как идентификация, также требует преобразования между GUID-х и ClassType-х

Как далеко вы должны попытаться пойти, когда развязку модулей в приложении?

  • просто введите интерфейс и пусть все остальные модули полагаются на интерфейс? (например, в описании типа IType)
  • еще разделить его, используя другие идентификаторы, такие как строки или GUID?

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

Как далеко вы должны блокировать свои модули?

ответ

1

Я отвожусь от размышлений о вашем отражении и просто посмотрю на идеи зависимостей.

Разделить то, что разумно отделить. Сцепление подразумевает, что если одна вещь меняется, значит, другая. Таким образом, ваш NewCode использует ClassType, если некоторые его аспекты изменяются, то yuou обязательно должен изменить NewCode - он не может быть полностью развязан. Какое из следующего вы хотите отделить?

  1. Семантика, какой классType делает.
  2. Интерфейс, как вы его называете.
  3. Реализация, как она реализована.

На мой взгляд, первые два являются разумными. Но, безусловно, для изменения реализации не требуется изменять NewCode. Итак, код для интерфейсов. Мы стараемся, чтобы интерфейсы были исправлены, мы склонны расширять их, а не изменять их, сохраняя их обратно совместимыми, если это вообще возможно. Иногда мы используем пары имя/значение, чтобы попытаться сделать интерфейс расширяемым, а затем ударить о типах ошибок, на которые вы ссылаетесь. Это компромисс между гибкостью и «безопасностью типа».

2

99% времени, если ваш дизайн основан на отражении, тогда у вас есть серьезные проблемы с дизайном.

Вообще говоря, что-то вроде

if (x is myclass) 
elseif (x is anotherclass) 
else 

является плохой дизайн, потому что пренебрегает полиморфизм. Если вы это делаете, то пункт x нарушает Принцип замены Лискова.

Также, учитывая, что у C++ уже есть RTTI, я не понимаю, почему вы изобретаете колесо. Вот что такое typeof и dynamic_cast.

+1

Полностью согласен. Reinventing RTTI почти всегда предает фундаментальное отсутствие понимания C++ OOP. – Reinderien

+0

У меня есть веские основания использовать дизайн на основе отражения, потому что мое приложение несколько особенное. Используя файл конфигурации, пользователи могут расширять datamodel с помощью дополнительных типов и свойств. Этого невозможно достичь без разработки на основе отражения, а также RTTI C++ здесь не помогает. Если бы не эта гибкость, я бы полностью согласился с вами. К сожалению, в этом случае я не могу. – Patrick

+1

@Patrick: Если типы, с которыми вы работаете, являются динамическими, в любом случае вы не сможете реализовать свою систему типов с точки зрения типов C++. Youd лучше с типом 'UserType', который может содержать sub' UserType ', который пользователь может затем расширить. –

0

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

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

Это мое мнение, во всяком случае.

Смежные вопросы