Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions authors.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion chapters/ajax/ajax_request_without_jquery.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ loadDataFromServer = ->

req.addEventListener 'readystatechange', ->
if req.readyState is 4 # ReadyState Compelte
if req.status is 200 or req.status is 304 # Success result codes
successResultCodes = [200, 304]
if req.status in successResultCodes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if req.status in [200, 304]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean you want to revert line 51 to if req.status in [200, 304] ?
Please see #discussion-diff-6180754 as for why we used the if req.status in successResultCodes syntax.

data = eval '(' + req.responseText + ')'
console.log 'data message: ', data.message
else
Expand Down
2 changes: 1 addition & 1 deletion chapters/arrays/max-array-value.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
77 changes: 77 additions & 0 deletions chapters/design_patterns/mediator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
layout: recipe
title: Mediator pattern
chapter: Design patterns
---

## Problem

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 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

{% 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}"
# 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

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()
new ModuleB()

{% endhighlight %}


## Discussion

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 into a parent class for convenience.