Example1 — how to enhance a big/complex function with your own logic

Suppose there is already a big function with huge logic, and you have the task to enhance it by appending your own logic to its end.


var  bigFunction  =  function()  {  // big logic console.log("big logic"); }
Copy the code

Of course if the big function is owned by you, you could directly append the enhancement, like below:


var  bigFunction  =  function()  {  // big logic console.log("big logic"); // append our own enhancement directly console.log("our own enhancement"); }
Copy the code

Another approach, if you would not like to touch the existing one, is to use a temporary variable to store the old bigFunction:


var _old = bigFunction;  bigFunction  =  function()  {  if  ( _old )  {  _old();  } console.log("our own enhancement");  }  bigFunction();  // After it is executed, console will print out
Copy the code

A Better Solution

We add a new function in Function.prototype:


Function.prototype.after  =  function( func ){  var _self =  this;  return  function()  {  var ret =  _self.apply(  this.arguments );  if  ( ret ===  false  )  {  return  false;  }  func.apply(  this.arguments);  returnret; }}Copy the code

This after function returns a new function, which will first call the original function, And then call the subsequent function passed in via variable “func” if the original function execution is successfully ( ret ! = false ).

Then just construct a new function using after function:


bigFunction = bigFunction.after(  function()  { console.log("our own logic");  });
Copy the code

Now when bigFunction() is executed, we get the same printout. With this approach, the temporary variable is avoided.

Example 2 — Write performance measurement code without polluting your productive code

Suppose in your application you have to create mass div node. You need to measure the creation performance. The most straightforward way is to get timestamp before and after creation. In order to get timestamp you cannot avoid to pollute Your productive code with two “new Date()” (or any other way for time measurement in JavaScript) as below.


var  append_doms  =  function()  {  var d =  new  Date(a);// dirty code - nothing to do with application logic!!! for( var i = 0; i < 100000; i++) { var div = document.createElement( "div"); document.body.appendChild(div); } // dirty code - nothing to do with application logic!!! console.log(" time consumed: " + ( new Date() - d)); };
Copy the code

A Better Solution

Using the idea of the first example, we create another method before in Function.prototype, which has similar design as Function.prototype.after:


Function.prototype.before  =  function( func)  {  var _self =  this;  return  function()  {  if  (  func.apply(  this.arguments) = = =false  )  {  return  false;  }  return  _self.apply(  this.arguments); }}Copy the code

With this approach, our productive code is clean — not any time measurement code there.


var  append_doms  =  function()  {  for(  var i =  0; i <  100000; i++)  {  var div = document.createElement(  "div"); document.body.appendChild(div); }};Copy the code

And we wrap the original function with before and after function we defined in Function.prototype:


var  log_time  =  function( func, log_name)  {  return func =  (  function()  {  var d;  return func.before(  function(){ d =  new  Date(a); }).after(function(){ console.log( log_name +  (  new  Date() - d)); }); }) (); };Copy the code

Now we get a new function log_time which is dedicatedly used for performance measurement. This new function actually consists of three parts:

(1) an anonymous function with body “d = new Date();”, chained by Function.prototype.before.

(2) the original append_doms

An anonymous function with body “console.log(log_name + (new Date() -d)); “, chained by the Function. The prototype. After.

We can elegantly call it via one line of code below to achieve the performance measurement.

log_time(append_doms, “consumed time: “)();

AOP in Java

Update on 2016-07-29: In Java it could be done elegantly via Spring framework. Please find more detail from this blog: [An example to explain why we need AOP – Aspect Oriented Programming](blogs.sap.com/?p=145576) .

Example 3 – Replace lots of if-else with Design Pattern “Chain of Responsibility”

Suppose I am responsible for developing a file upload function and the upload could be finished by various approach if each feature is supported by client side. The priority is listed below:

// Priority: ActiveX > HTML5 > Flash > Form(default)

If means for example, if ActiveX is supported by client’s browser, it should be used. The default is upload via form, if all previous tries have failed.


function  isActiveXSupported(){  / /... return false; } function isHTML5Supported(){ //... return true; } function isFlashSupported(){ //... return false; }
Copy the code

The codes above just simulate the situation that HTML5 upload should be used, since its preceding attempt, isActiveXSupported, returns false. In order to get the proper upload service, we have to code lots of tedious IF-ELSE evaluation:


var uploadAPI;  if  (  isActiveXSupported())  {  // lots of initialization work uploadAPI = { "name": "ActiveX"}; } else if( isHTML5Supported()) { // lots of initialization work uploadAPI = { "name": "HTML5"}; } else if( isFlashSupported()) { // lots of initialization work uploadAPI = { "name": "Flash"}; } else { // lots of initialization work uploadAPI = { "name": "Form"}; } console.log(uploadAPI); // HTML5 service is got
Copy the code

A Better Solution

We do some minor change on Function.prototype.after:


Function.prototype.after  =  function( func ){  var _self =  this;  return  function()  {  var ret =  _self.apply(  this.arguments );  if  ( ret )  {  return ret;  }  return  func.apply(  this.arguments); }}Copy the code

Now if the execution of original function is successfully ( returns true ), we terminate the function chain, that is, we don’t pass the responsibility chain to its subsequent function passed via func.

With this approach, there is no more IF-ELSE evaluation. In fact, now we spread the evaluation into the dedicated initialization function of each API:


var  getActiveX  =  function()  {  try  {  // lots of initialization work return { "name": "ActiveX"}; } catch (e) { // user broswer does not support ActiveX return null; } } var getHTML5 = function() { try { // lots of initialization work return { "name": "HTML5"}; } catch (e) { // user broswer does not support HTML5 return null; } } var getFlash = function() { try { // lots of initialization work return { "name": "Flash"}; } catch (e) { // user broswer does not support Flash return null; } } var getForm = function() { return { "name": "Form"}; } ` ` `

Now in order to get appropriate API, we just use single line:

> var uploadAPI = getActiveX.after(getHTML5).after(getFlash).after(getForm)();

This design idea is actually the so called “Chain ofThe Responsibility ". Simple speakingfunction in the beginning of chain ( in my example, it is getActiveX ) will analyze whether it is able to resolve the task. If yes.the whole statement returns.task is over. Otherwise.it simply delegate the task to the next node in the chain#.Example4 -eliminate lots of IF-ELSE in validity check via Strategy Design Pattern

For example.before we assemble the request payload to send OData request via OData API.we must perform various validity check on the user input. If you have a page with lots of UI elements.usually it will lead to lots of IF-ELSEIF-ELSEIF validity check code spread in your application. ` ` `javascript

var  send  =  function()  {  var value = input.value;  if( value.length ===  ' '  )  {  return  false;  }  else  if( value.length >  MAX_LENGTH)  {  return  false; }...// LOTS OF other rules to be checked else { // all check passes, now ready to call OData API } }
Copy the code

A Better Solution

Instead of directly coding all those validity checks in the application, We can first put the rules in a JavaScript object (so called “Strategy” in Design Pattern):


var valid_rules =  {  not_empty:  function( value )  {  returnvalue.length ! = =' ';  },  max_length:  function( value )  {  returnvalue.length <= MAX_LENGTH ; }}Copy the code

With strategy ready, Now we can simply write the validity check function in a generic way. It doesn’t know any detail about validity rules. but simply scan rules configured in strategy object one by one. If any check fails, The whole function will return false — check not pass.


var  valid_check  =  function()  {  for(  var i in valid_rules )  {  if  ( vali_rules[i].apply(  this.arguments) = = =false  )  {  return  false; }}}Copy the code

Finally the send function could be reduced as:


var  send  =  function( value )  {  if  (  valid_check( value )  ===  false  )  {  return;  }  // all check passes, now ready to call OData API }
Copy the code