From 4a6f57fdea70cc38a0b64d890ee659b649d47e4f Mon Sep 17 00:00:00 2001 From: Julien Date: Mon, 9 Sep 2013 17:24:48 +0800 Subject: [PATCH 1/6] Write page for the Mediator Design Pattern. --- authors.md | 1 + chapters/design_patterns/mediator.md | 78 ++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 chapters/design_patterns/mediator.md diff --git a/authors.md b/authors.md index be4922c..5946947 100644 --- a/authors.md +++ b/authors.md @@ -21,6 +21,7 @@ The following people are totally rad and awesome because they have contributed r * Frederic Hemberger * Mike Hatfield *oakraven13@gmail.com* * [Anton Rissanen](http://github.com/antris) *hello@anton.fi* +* [Julien Buty](http://github.com/nepsilon) [julien@nepsilon.net](mailto:julien@nepsilon.net) * ...You! What are you waiting for? Check out the [contributing](/contributing) section and get cracking! # Developers diff --git a/chapters/design_patterns/mediator.md b/chapters/design_patterns/mediator.md new file mode 100644 index 0000000..a8f9b03 --- /dev/null +++ b/chapters/design_patterns/mediator.md @@ -0,0 +1,78 @@ +--- +layout: recipe +title: Mediator pattern +chapter: Design patterns +--- + +## Problem + +Imagine 100 air planes in the sky in need to land at airport A, which only accept one plane landing at a time. +A first strategy would be for each plane to ask to each of its peers who need to go first, second, etc. +This would be a very time consuming, error prone and quite tedious task. +A better option would be to all planes to report to a control tower, and having it sorting out the landing scheduling. +Each plane would then simply need to tell the control tower it needs to land, and wait for a reply from the control tower. +With this latter approach, a given plane doesn't need to know about other planes up there. +All communication can now be centralized and synchronously broadcasted to all. + +Similarly, we can face this problem when developing software. +When an application is made of several modules, each in charge of its own task but depending on the state of some other modules, we can have each module listening directly to each of its dependency, maybe through the Observer pattern, and be notified when a change occur. +The problems with this approach are the same as with the planes all talking directly to each other. +We have tight coupling between modules, if a dependency fails our module fails and each module has to be aware of the existence of its dependencies. +A better approach would introduce loose coupling of modules and would have their communication centralized. +With such an approach, each module doesn't need to know about the existence of other modules, but simply be listening for events some of them may fire. +The mediator pattern is the one that will allow all of that. + +## Solution + +{% highlight coffeescript %} + +# Our mediator class +class Mediator + + constructor: -> + @channels = {} + + subscribe: (event, context, callback) => + @channels[event] or= [] + @channels[event].push callback.bind context + + publish: (event, args...) => + return false if not @channels[event] + callback(args) for callback in @channels[event] + + wrap: (obj) -> + obj.subscribe = @subscribe + obj.publish = @publish + obj + +# Instantiate our Mediator +MEDIATOR = new Mediator() + +# Module A +class ModuleA + + constructor: -> + MEDIATOR.wrap @ # We add event capabilities to our module + @subscribe 'hello', @, (payload) -> console.log "(ModuleA) Received event 'hello' with payload: #{payload}" + +# Module B +class ModuleB + + constructor: -> + MEDIATOR.wrap @ # We add event capabilities to our module + @publish 'hello', 'I am moduleB and I just published!' + +# Instantiate our 2 modules +new ModuleA() +new ModuleB() + +{% endhighlight %} + + +## Discussion + +As you can see we now have inter-module communication without having each module dependent on the existence of other. +ModuleA won't fail if ModuleB isn't there and vice-versa. +Such an approach makes a lot of sense when developing applications such as [Netvibes](http://netvibes.com), [Google Ig](http://google.com/ig) or [Chartbeat](https://chartbeat.com/) dashboards. + +The `MEDIATOR.wrap` step could also be abstracted away in a mother class for more convenience. From 391cd09ce5d2ee6097875aa1cbe3862a516d518a Mon Sep 17 00:00:00 2001 From: Julien Date: Mon, 9 Sep 2013 17:29:23 +0800 Subject: [PATCH 2/6] Add alternative syntax in comment. --- chapters/design_patterns/mediator.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chapters/design_patterns/mediator.md b/chapters/design_patterns/mediator.md index a8f9b03..b215b47 100644 --- a/chapters/design_patterns/mediator.md +++ b/chapters/design_patterns/mediator.md @@ -54,6 +54,8 @@ class ModuleA constructor: -> MEDIATOR.wrap @ # We add event capabilities to our module @subscribe 'hello', @, (payload) -> console.log "(ModuleA) Received event 'hello' with payload: #{payload}" + # The 2 lines above could also have been written: + # MEDIATOR.subscribe 'hello', @, (payload) -> console.log "Received event 'hello' with payload: #{payload}" # Module B class ModuleB @@ -61,6 +63,8 @@ class ModuleB constructor: -> MEDIATOR.wrap @ # We add event capabilities to our module @publish 'hello', 'I am moduleB and I just published!' + # The 2 lines above could also have been written: + # MEDIATOR.subscribe 'hello', @, (payload) -> console.log "Received event 'hello' with payload: #{payload}" # Instantiate our 2 modules new ModuleA() From 530bcb6d0f1365dd23406d9d173119ada97283ba Mon Sep 17 00:00:00 2001 From: Angela Date: Tue, 10 Sep 2013 13:55:58 +0800 Subject: [PATCH 3/6] Update mediator.md Rewrite Draft --- chapters/design_patterns/mediator.md | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/chapters/design_patterns/mediator.md b/chapters/design_patterns/mediator.md index b215b47..a80fca1 100644 --- a/chapters/design_patterns/mediator.md +++ b/chapters/design_patterns/mediator.md @@ -6,21 +6,17 @@ chapter: Design patterns ## Problem -Imagine 100 air planes in the sky in need to land at airport A, which only accept one plane landing at a time. -A first strategy would be for each plane to ask to each of its peers who need to go first, second, etc. -This would be a very time consuming, error prone and quite tedious task. -A better option would be to all planes to report to a control tower, and having it sorting out the landing scheduling. -Each plane would then simply need to tell the control tower it needs to land, and wait for a reply from the control tower. -With this latter approach, a given plane doesn't need to know about other planes up there. +Imagine 100 airplanes that need to land in airport A, which only accept one airplane landing at a time. +First strategy is to have every plane asking all its peers for landing order. This would be a very time consuming, error prone and quite tedious task. +A better option is to have all airplanes report directly to a control tower, which determines the landing schedule for all airplanes. +Each plane then simply request landing permission from the control tower, and wait for a reply. +With the latter approach, a given plane doesn't need to know about all other planes. All communication can now be centralized and synchronously broadcasted to all. Similarly, we can face this problem when developing software. -When an application is made of several modules, each in charge of its own task but depending on the state of some other modules, we can have each module listening directly to each of its dependency, maybe through the Observer pattern, and be notified when a change occur. -The problems with this approach are the same as with the planes all talking directly to each other. -We have tight coupling between modules, if a dependency fails our module fails and each module has to be aware of the existence of its dependencies. -A better approach would introduce loose coupling of modules and would have their communication centralized. -With such an approach, each module doesn't need to know about the existence of other modules, but simply be listening for events some of them may fire. -The mediator pattern is the one that will allow all of that. +When an application is composed of several modules, each module is in charge of its own task but also dependent on the state of other modules. We can have each module listening directly to each of its dependencies, maybe through the Observer pattern, and be notified when a change occur. +The problems with this approach are the same as having airplanes listening to each other. When we have tight coupling between modules, every module has to watch out for its dependencies. +A better approach would be to introduce loose coupling of modules and centralize inter-module communication. With such an approach, each module doesn't need to know about the existence of other modules, but simply listen for events they fire. This is the mediator pattern. ## Solution @@ -75,8 +71,7 @@ new ModuleB() ## Discussion -As you can see we now have inter-module communication without having each module dependent on the existence of other. -ModuleA won't fail if ModuleB isn't there and vice-versa. +As you can see we now have inter-module communication without having modules looking out for their dependencies. Hence, ModuleA won't fail if ModuleB isn't there and vice-versa. Such an approach makes a lot of sense when developing applications such as [Netvibes](http://netvibes.com), [Google Ig](http://google.com/ig) or [Chartbeat](https://chartbeat.com/) dashboards. -The `MEDIATOR.wrap` step could also be abstracted away in a mother class for more convenience. +The `MEDIATOR.wrap` step could also be abstracted into a parent class for convenience. From f31231149eb335c57a110347051e547ea49f201c Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 5 Sep 2013 19:06:11 +0800 Subject: [PATCH 4/6] Bring CoffeeScript idiom to conditional statement. An advantage of CoffeeScript compared to JavaScript is its ability to check for array membership with the `in` keyword. A feature it borrowed from Python. --- chapters/ajax/ajax_request_without_jquery.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ajax/ajax_request_without_jquery.md b/chapters/ajax/ajax_request_without_jquery.md index 5956548..7f69c93 100644 --- a/chapters/ajax/ajax_request_without_jquery.md +++ b/chapters/ajax/ajax_request_without_jquery.md @@ -47,7 +47,7 @@ loadDataFromServer = -> req.addEventListener 'readystatechange', -> if req.readyState is 4 # ReadyState Compelte - if req.status is 200 or req.status is 304 # Success result codes + if req.status in [200, 304] # Success result codes data = eval '(' + req.responseText + ')' console.log 'data message: ', data.message else From 50d4f55d8fb33268caf38c53c977c2496bad7b54 Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 5 Sep 2013 19:29:49 +0800 Subject: [PATCH 5/6] Amount takes only 1 'm'. --- chapters/arrays/max-array-value.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/arrays/max-array-value.md b/chapters/arrays/max-array-value.md index ce3adc1..25f1472 100644 --- a/chapters/arrays/max-array-value.md +++ b/chapters/arrays/max-array-value.md @@ -26,4 +26,4 @@ Alternatively, it's possible to use ES5 `reduce` method. For backward compatibil ## Discussion -`Math.max` compares every argument and returns the largest number from arguments. The ellipsis (`...`) converts every array value into argument which is given to the function. You can also use it with other functions which take variable ammount of arguments, such as `console.log`. +`Math.max` compares every argument and returns the largest number from arguments. The ellipsis (`...`) converts every array value into argument which is given to the function. You can also use it with other functions which take variable amount of arguments, such as `console.log`. From 2a5dbac5f01a0837e5e7d8e9a3860c3e43edd6b7 Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 5 Sep 2013 21:29:53 +0800 Subject: [PATCH 6/6] Improve readability. --- chapters/ajax/ajax_request_without_jquery.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chapters/ajax/ajax_request_without_jquery.md b/chapters/ajax/ajax_request_without_jquery.md index 7f69c93..d95713c 100644 --- a/chapters/ajax/ajax_request_without_jquery.md +++ b/chapters/ajax/ajax_request_without_jquery.md @@ -47,7 +47,8 @@ loadDataFromServer = -> req.addEventListener 'readystatechange', -> if req.readyState is 4 # ReadyState Compelte - if req.status in [200, 304] # Success result codes + successResultCodes = [200, 304] + if req.status in successResultCodes data = eval '(' + req.responseText + ')' console.log 'data message: ', data.message else