как программист кипятит воду в чайнике? 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;
}ключевой момент — все участки которые можно было вынести в одно место — вынесены в него. Так мы гарантируем унифицированное поведение для всех однородных методов ( += и + в нашем случае) а также однородное поведение конструкторов класса. То есть не будет поведения где один конструктор работает правильно, а другой не инициализирует половину переменных.
Каждый раз когда перед вами становится большая задача по переделке логики — подумайте — может быть существует уже решение делающее все почти так как вам нужно. Решение которое можно слегка адаптировать под свои нужды.
Было бы интересно послушать ваши простые решения сложных проблем
