1
0
mirror of https://github.com/tmrts/go-patterns.git synced 2024-11-22 13:06:09 +03:00

Realisation of behavioral-mediator pattern

This commit is contained in:
Artjoms Nemiro 2017-10-09 20:59:50 +03:00
parent f978e42036
commit 3bb0d5199d
3 changed files with 154 additions and 1 deletions

View File

@ -38,7 +38,7 @@ A curated collection of idiomatic design & application patterns for Go language.
|:-------:|:----------- |:------:| |:-------:|:----------- |:------:|
| [Chain of Responsibility](/behavioral/chain_of_responsibility.md) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✘ | | [Chain of Responsibility](/behavioral/chain_of_responsibility.md) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✘ |
| [Command](/behavioral/command.md) | Bundles a command and arguments to call later | ✘ | | [Command](/behavioral/command.md) | Bundles a command and arguments to call later | ✘ |
| [Mediator](/behavioral/mediator.md) | Connects objects and acts as a proxy | | | [Mediator](/behavioral/mediator.md) | Connects objects and acts as a proxy | |
| [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ | | [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ |
| [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ | | [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ |
| [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ | | [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ |

43
behavioral/mediator.md Normal file
View File

@ -0,0 +1,43 @@
# Mediator Pattern
The [mediator pattern](https://en.wikipedia.org/wiki/Mediator_pattern) allows to objects no longer communicate directly with each other, but instead communicate through the mediator. This reduces the dependencies between communicating objects, thereby reducing coupling. In plain words, your object(s) must know about "mediator" to communicate with another object across a "mediator". So, that allows to "mediator" implements cooperative behavior by sending a request to one or more.
## Implementation
To implement you will need:
- ``Mediator interface`` - an intermediary describing the organization of the process of information exchange between objects
- ``The Concrete Mediator``, which implements the Mediator interface
- ``Colleague interface`` - describing the organization of the process of interaction of collaborative objects with an object of the Mediator type
- ``The Concrete Colleague`` that implements the Colleague interface. Each object-colleague knows only about the object-mediator. All objects-colleagues exchange information only through an intermediary.
## Usage
### Mediator interface and Concrete Mediator to communicate between objects
```go
type Mediator interface {
AddCollegue(c Colleague)
Communicate(c Colleague)
}
type ConcreteMediator struct {
Colleague *list.List
}
```
### Colleague interface and Concrete Colleague, all communications must be possible through ``mediator.Communicate()`` in ``ConcreteColleague``
```go
type Colleague interface {
GetData() interface{}
}
type ConcreteColleague struct {
mediator ConcreteMediator
}
```
For better explanation watch short code of chat room example: ([on playground](https://play.golang.org/p/lsBkEEfkCv)) or see local example [mediator/main.go](mediator/main.go)
## Rules of Thumb
GoF design patterns recommends use when:
- A set of objects communicate in well-defined but a complex way. So resulting are unstructured and complex to understand.
- Reusing an object is difficult because it refers and communicates with many others objects.
- A behavior that is distributed between objects should be customizable without a subclassing.
Also, the mediator can be implemented with using the observer pattern, colleague classes act as Subjects, sending notifications to the mediator whenever they change state.

110
behavioral/mediator/main.go Normal file
View File

@ -0,0 +1,110 @@
package main
import (
"container/list"
"fmt"
"time"
)
/*
Mediator
*/
// ChatRoomMediator main interface between colleague and mediator
type ChatRoomMediator interface {
JoinUser(uc UserColleague)
SendMessage(uc UserColleague)
}
// ChatRoom is a concrete mediator with all joined colleagues
type ChatRoom struct {
users *list.List
}
// JoinUser join concrete colleagues to concrete mediator (ChatRoom)
func (cr *ChatRoom) JoinUser(uc UserColleague) {
cr.users.PushBack(uc)
}
// SendMessage use mediator to communicate between colleagues
func (cr *ChatRoom) SendMessage(uc UserColleague) {
for e := cr.users.Front(); e != nil; e = e.Next() {
if e.Value == uc {
ct := time.Now().Format(time.Kitchen)
fmt.Printf("|%s| %s -> : %s \n", ct, uc.GetName(), uc.GetMessage())
}
}
}
// NewChatRoom creates concrete mediator
func NewChatRoom() *ChatRoom {
return &ChatRoom{list.New()}
}
/*
Colleague
*/
// UserColleague implements colleague to communicate with mediator
type UserColleague interface {
GetName() string
GetMessage() string
}
// User represents concrete colleague
type User struct {
name string
message string
mediator ChatRoomMediator
}
// GetMessage returns last wrote message
func (u *User) GetName() string {
return u.name
}
// GetMessage returns last wrote message
func (u *User) GetMessage() string {
return u.message
}
// WriteMessage concrete colleague send's message via mediator
func (u *User) writeMessage(message string) {
u.message = message
// Ask mediator to send message
u.mediator.SendMessage(u)
}
// AddUser will make relationship between concrete mediator and concrete colleague
func AddUser(name string, chatRoom ChatRoomMediator) *User {
// Create new colleague(user) and join mediator(room)
user := &User{name: name, message: "", mediator: chatRoom}
// Join colleague(user) to mediator(room)
chatRoom.JoinUser(user)
return user
}
/*
Showcase
*/
func main() {
// Create mediator
barrelHouse := NewChatRoom()
// Create colleagues and join to mediator
JohnInBarrelHouse := AddUser("John Doe", barrelHouse)
AlmaInBarrelHouse := AddUser("Alma", barrelHouse)
// Now colleagues will send messages via mediator
JohnInBarrelHouse.writeMessage("Hello gophers")
AlmaInBarrelHouse.writeMessage("Hey John!")
JohnInBarrelHouse.writeMessage("Alma, let's discuss Mediator pattern?")
// Example of output
// |8:33PM| John Doe -> : Hello gophers
// |8:33PM| Alma -> : Hey John!
// |8:34PM| John Doe -> : Alma, let's discuss Mediator pattern?
}