как программист кипятит воду в чайнике? 1. Набирает воду в чайник 2. Ставит чайник на огонь 3. Ждет пока тот не вскипит как программист кипятит воду в чайнике если в нем уже есть вода? 1. Выливает воду из чайника что сводит задачу к уже решенной (старый анекдот)
Для каждой задачи есть куча разных решений. Умных, глупых, быстрых, хитрых. В реальной жизни решения делятся на два типа — те которые работают и все остальные.
Представьте себе что у вас есть сложный код ( свой или чужой ), и нужно серьезно повлиять на логику его работы? Конечно можно залезть в глубину, исследовать зависимости, подумать над возможными последствиями и проблемами. Даже для своего кода это не просто. Для чужого же — сложность просто дикая.
Когда перед вами ставится подобная задача — самое время вспомнить про паттерн «вылить воду из чайника» (звучит почти как китайская стратегемма =) )
И вместо проделывая сложной задачи — свести ее к решению уже существующей. Таким образом вы не модифицируете сложный, и потенциально опасный код, а пишете свой, небольшой кусочек кода, в правильности работы которого легко убедиться.
примеры
Когда-то давно наша компания создавала БД для Lotus Notes. Но увы клиентам было непривчно нажимать Tab для перехода на другую ячейку таблицы — поскольку они привыкли к Экселю, где для перехода нужно было нажать Enter. Мы не нашли ни одного стандартного средства для замены клавиши Таб на Энтер, и поэтому прибегли к следующему решению. Повесили клавиатурный хук который замещал нажатия Enter на Tab если нажатие имело место быть в нужных нам таблицах нашего приложения.
другой пример — джаббер транспорты
джаббер клиенту не нужно знать о существовании других протоколов. Он работает только по xmpp. Переводом занимается джаббер сервер.
ну и пример из кода
class Int { public: Int(const int iv) :i(iv) {} Int(const Int& copy) { *this = copy; } // констуркторы копировая и присваивания тут объеденены. // Так если у вас добавится новая переменная в класс - // нужно будет добавить ее только в одно место в коде, а не в несколько Int& operator=(const Int& copy) { i = copy.i; return *this; } Int& operator++() { i++; return *this; } // реализуем постфиксный ++ через префиксный const Int operator++(int) { return ++(*this); } // а += через конструктор Int operator+=(int v) { return Int(i+v); } private: int i; }; // оператор+ использующий уже существующий += Int operator+(const Int& i, const int iv) { Int intVal(i); intVal+=iv; return intVal; }
ключевой момент — все участки которые можно было вынести в одно место — вынесены в него. Так мы гарантируем унифицированное поведение для всех однородных методов ( += и + в нашем случае) а также однородное поведение конструкторов класса. То есть не будет поведения где один конструктор работает правильно, а другой не инициализирует половину переменных.
Каждый раз когда перед вами становится большая задача по переделке логики — подумайте — может быть существует уже решение делающее все почти так как вам нужно. Решение которое можно слегка адаптировать под свои нужды.
Было бы интересно послушать ваши простые решения сложных проблем