📜 ⬆️ ⬇️

Pattern - Pour water out of the kettle

  How does a programmer boil water in a kettle?
 1. Gathers water into the kettle
 2. Put the kettle on the fire
 3. Waits until he boils

 How does a programmer boil water in a kettle if there is already water in it?
 1. Pours water from the kettle which reduces the task to the already solved one.
 (old joke) 


For each task there are a bunch of different solutions. Smart, stupid, fast, cunning. In real life, solutions are divided into two types - those that work and all the rest.

Imagine that you have a complex code (yours or someone else's), and you need to seriously influence the logic of its work? Of course, you can get into the depths, explore dependencies, think about possible consequences and problems. Even for your code it is not easy. For someone else, the complexity is simply wild.

When you are faced with a similar task - it's time to recall the “pour water from the kettle” pattern (it sounds almost like a Chinese strategy =))
And instead of doing a complex task - to reduce it to the solution of an existing one. Thus, you do not modify complex and potentially dangerous code, but write your own, small piece of code, the correctness of which is easily verified.
')
examples
Once upon a time, our company created a database for Lotus Notes. But alas, customers had no need to press Tab to go to another table cell - because they were used to Excel, where they had to press Enter to go. We did not find any standard means for replacing the Tab key with Enter, and therefore resorted to the following solution. We hung up a keyboard hook that replaced pressing Enter on the Tab if the click took place in the tables of our application we need.

another example is jabber transports
Jabber client does not need to know about the existence of other protocols. It works only on xmpp. Translation deals with jabber server.

Well, an example from the code
  class int
 {
 public:
     Int (const int iv)
     : i (iv)
     {}

     Int (const int & copy)
     {
         * this = copy;
     }

     // Copy and assignments are merged here.
     // So if you add a new variable to the class -
     // you will need to add it only to one place in the code, and not to several
     Int & operator = (const Int & copy)
     {
         i = copy.i;
         return * this;
     }

     Int & operator ++ ()
     {
         i ++;
         return * this;
     }
    
     // implement postfix ++ through prefix
     const int operator ++ (int)
     {
         return ++ (* this);
     }

     // a + = through the constructor
     Int operator + = (int v)
     {
         return int (i + v);
     }

 private:
     int i;
 };

 // operator + using already existing + =
 Int operator + (const int & i, const int iv)
 {
     Int intVal (i);
     intVal + = iv;
     return intVal;
 } 

the key point - all the plots that could be taken out in one place - are brought into it So we guarantee uniform behavior for all homogeneous methods (+ = and + in our case) as well as uniform behavior of class constructors. That is, there will be no behavior where one constructor works correctly and the other does not initialize half of the variables.

Every time when you are faced with a big task of remaking logic - think about it - maybe there is already a solution that does everything almost as you need. A solution that can be slightly adapted to your needs.

It would be interesting to listen to your simple solutions to complex problems.

Source: https://habr.com/ru/post/64425/


All Articles