tag:blogger.com,1999:blog-654279083390275842.post7556338331529673503..comments2024-03-19T12:22:43.654+03:00Comments on Размышлизмы eao197: В поиске решения "Можно ли заставить компилятор проверять изменение принципов работы компонентов?"eao197http://www.blogger.com/profile/17283739752119445290noreply@blogger.comBlogger2125tag:blogger.com,1999:blog-654279083390275842.post-56742048799803660092009-02-17T20:05:00.000+02:002009-02-17T20:05:00.000+02:00Здесь фишка не столько в том, что можно позволить ...Здесь фишка не столько в том, что можно позволить производным от s_iface_t классам. Сколько в том, как сам s_iface_t и его единственная реализация s_component_t могут измениться со временем.<BR/><BR/>Смотри какая ситуация: есть два компонента M и S. Компонент M видит S через интерфейс s_iface_t. Для интерфейса s_iface_t есть только одна реализация -- s_component_t (другие могут быть только в отладочных целях). Так вот, нужно на уровне интерфейса выразить зависимость M от конкретной логики работы s_component_t.<BR/><BR/>Если M видит s_iface_t:query_state() как void-метод, то в какой-то очередной версии S какой-то другой разработчик может изменить логику поведения query_state другим образом. Грубо говоря, выбросит виртуальный метод query_state_impl() и переделает реализацию query_state(). В результате поведение компонента S может измениться. А компонент M об этом даже не узнает.<BR/><BR/>А вот такой вариант, с возвратом из query_state() специального типа, от таких изменений защищает.<BR/><BR/>Совсем другой вопрос -- нужны ли эти навороты и должен ли M зависеть от логики поведения S. По-хорошему, наверное, не нужны и не должен. Но раз уж я однажды попал в такую ситуацию, то почему бы не придумать способ описания таких зависимостей на будущее? ;)eao197https://www.blogger.com/profile/17283739752119445290noreply@blogger.comtag:blogger.com,1999:blog-654279083390275842.post-14213365952142355932009-02-17T17:48:00.000+02:002009-02-17T17:48:00.000+02:00Возможно я чего-то не догнал, но именно для этого ...Возможно я чего-то не догнал, но именно для этого предназначен NVI. Ну и вообще, если требуется соответствие каким-то требованиям или предоставлять меньше свободы производным классам (в хорошем смысле), то лучше использовать поток управления снизу-вверх (скелет алгоритма определяет базовый класс, а произвольный только реализует какие-то детали), а не сверху-вниз (скелет алгоритма можно определить свой в каждом производном классе, а функции из базового используются только как вспомогательные).<BR/><BR/>class s_iface_t<BR/>{<BR/>public:<BR/> void query_state()<BR/> {<BR/> // скелет алгоритма, включая контракт, зашиты в базовый класс<BR/> ...<BR/> query_state_impl();<BR/> ...<BR/> send_state_notify();<BR/> ...<BR/> }<BR/><BR/>private:<BR/> // производный класс может лишь определить какие-то детали<BR/> // нарушить контракт он не может<BR/> virtual void query_state_impl() = 0;<BR/>};<BR/><BR/>class s_component_t : public s_iface_t<BR/>{<BR/>private:<BR/> virtual void query_state_impl()<BR/> {<BR/> ...<BR/> }<BR/>};Dmitry Vyukovhttps://www.blogger.com/profile/10137998824493472445noreply@blogger.com