У меня есть функция User::func()
(обратный вызов), которая будет вызываться классом шаблона (Library<T>
).
На первом этапе разработки все знают, что func()
служит только для этой единственной цели.
Несколько месяцев спустя большинство участников забывают, для чего предназначен func()
.
После серьезного рефакторинга некоторые программисты иногда удаляют func()
. .
Сначала я вообще не думал, что это проблема.
Однако после того, как я несколько раз сталкивался с этой схемой, я решил, что мне нужны контрмеры.
Вопрос
Как это красиво задокументировать? (мило и лаконично и без дополнительных затрат на ЦП)
Пример
Вот упрощенный код:-
(Реальная проблема заключается в разбросе около 10+ библиотечных файлов, 20+ пользовательских файлов и 40+ функций.)
Библиотека.h
template<class T> class Library{
public: T* node=nullptr;
public: void utility(){
node->func(); //#1
}
};
User.h
class User{
public: void func(){/** some code*/} //#1
//... a lot of other functions ...
// some of them are also callback of other libraries
};
main.cpp
int main(){
Library<User> li; .... ; li.utility();
}
Мои плохие решения
1. Комментарий/документ
В качестве первого обходного пути я обычно добавляю такой комментарий: -
class User{
/** This function is for "Library" callback */
public: void func(){/** some code*/}
};
Но он довольно быстро загрязняется — мне приходится добавлять его в каждую «функцию» в каждом классе.
2. Переименуйте "func()"
В реальном случае я обычно добавляю префикс имени функции следующим образом: -
class User{
public: void LIBRARY_func(){/** some code*/}
};
Это очень заметно, но имя функции теперь очень длинное.
(особенно когда Library
-класс имеет более длинное имя класса)
3. Виртуальный класс с "func()=0"
Я рассматриваю возможность создания абстрактного класса в качестве интерфейса для обратного вызова.
class LibraryCallback{
public: virtual void func()=0;
};
class User : public LibraryCallback{
public: virtual void func(){/** some code*/}
};
Создается ощущение, что func()
означает что-то совершенно внешнее. :)
Однако мне приходится жертвовать стоимостью виртуальных вызовов (v-table).
В критических для производительности случаях я не могу себе этого позволить.
4. Статическая функция
(идея от Daniel Jour в комментарии, спасибо!)
Почти 1 месяц спустя, вот как я использую: -
Библиотека.h
template<class T> class Library{
public: T* node=nullptr;
public: void utility(){
T::func(node); //#1
}
};
User.h
class User{
public: static void func(Callback*){/** some code*/}
};
main.cpp
int main(){
Library<User> li;
}
Это, вероятно, чище, но все еще не хватает самодокумента.
LibraryCallback* node
. - person Code-Apprentice   schedule 17.04.2017T* t
внутриclass Library{}
. Я согласен с тем, что виртуальный класс обеспечивает большое удобство при кодированииLibrary
. - person javaLover   schedule 17.04.2017User
классов (с разнойfunc
реализацией), верно? Если сразу не очевидно, чтоfunc
имеет какое-либо применение и поэтому удаляется ... тогда, возможно, действительно было бы лучше иметьfunc
не как функцию-членUser
, а, возможно, как свободную функцию или член некоторого вспомогательного класса? - person Daniel Jour   schedule 18.04.2017Library<User,&freeFunc>
илиLibrary<User,HelperClass>
, что немного грязнее. .... Но все же, я думаю, что ваша идея удобна и уникальна. ..... Если вы опубликуете это, я проголосую за это. Благодарить! XD - person javaLover   schedule 18.04.2017User::func()
доступ к закрытым функциямUser
? В противном случае можно использовать класс свойств (отделяет реализацию от реализацииUser
и делает очевидным, что это связь междуUser
иLibrary
). - person chtz   schedule 17.05.2017