Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add mediator design pattern #352

Merged
merged 2 commits into from
Apr 19, 2024
Merged
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
345 changes: 344 additions & 1 deletion content/chapter 9/behavioral patterns/9.3.4-mediator.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,347 @@ title: '9.3.4 الگو Mediator'
slug: go-mediator-pattern
weight: 176004
---
الگو Mediator...


## 9.3.4.1-**الگوی طراحی Mediator**

الگوی طراحی واسطه (**Mediator**)، یک الگوی رفتاری است که به شما امکان می‌دهد تا وابستگی‌های درهم‌تنیده بین اشیاء را کاهش دهید. این الگو ارتباط مستقیم بین اشیاء را محدود می‌کند و آن‌ها را مجبور می‌سازد تا تنها از طریق یک شیء واسطه با هم همکاری کنند.

### 9.3.4.2-**مشکل**

فرض کنید یک جعبه dialog برای ایجاد و ویرایش پروفایل کاربران دارید. این جعبه dialog شامل کنترل‌های مختلف فرم مانند فیلدهای متنی، کادرهای انتخابی(checkbox)، دکمه‌ها و غیره می‌شود.

![mediator-problem1](../../../assets/img/content/chapter9/designPatterns/mediator-problem1-en.png)

ممکن است برخی از عناصر فرم با سایرین تعامل داشته باشند. برای مثال، انتخاب checkbox "من یک سگ دارم" ممکن است یک فیلد متنی پنهان برای وارد کردن نام سگ را نمایش دهد. مثال دیگر دکمه “ثبت” است که باید قبل از ذخیره اطلاعات، صحت مقادیر همه فیلدها را تایید کند.

![mediator-problem2](../../../assets/img/content/chapter9/designPatterns/mediator-problem2.png)


با پیاده‌سازی مستقیم این منطق درون کد عناصر فرم، باعث می‌شوید استفاده‌ی مجدد از کلاس‌های این عناصر در فرم‌های دیگر برنامه بسیار دشوار شود. برای نمونه، به دلیل وابستگی به فیلد متن سگ، نمی‌توانید از کلاس کادر انتخاب مذکور در فرم دیگری استفاده کنید. در این حالت، مجبور هستید یا از تمام کلاس‌های درگیر در نمایش فرم پروفایل استفاده کنید، یا هیچ‌کدام را به کار نبرید.

### 9.3.4.3- **راه‌حل**

الگوی طراحی Mediator پیشنهاد می‌کند که تمام ارتباط‌های مستقیم بین اجزایی که می‌خواهید مستقل از یکدیگر باشند را متوقف کنید. در عوض، این اجزا باید به صورت غیرمستقیم با هم همکاری کنند، یعنی با فراخوانی یک شیء واسطه‌ی خاص که تماس‌ها را به اجزای مناسب هدایت می‌کند. در نتیجه، اجزا تنها به یک کلاس واسطه وابسته می‌شوند، نه اینکه به ده‌ها جزء همکار دیگرشان وابسته باشند.

در مثال فرم ویرایش پروفایل، خود کلاس باکس گفتگو می‌تواند نقش واسطه را ایفا کند. به احتمال زیاد، کلاس جعبه dialog از قبل از تمام زیرمجموعه‌هایش آگاه است، بنابراین حتی نیازی به معرفی وابستگی‌های جدید به این کلاس نخواهید داشت.

![mediator-solution1-en](../../../assets/img/content/chapter9/designPatterns/mediator-solution1-en.png)

مهم‌ترین تغییر در عناصر واقعی فرم اتفاق می‌افتد. بیایید دکمه‌ی “ثبت” را در نظر بگیریم. پیش از این، هر بار که کاربر روی دکمه کلیک می‌کرد، این دکمه مجبور بود صحت مقادیر تمام عناصر فرم مجزا را تایید کند. حالا تنها وظیفه‌ی دکمه، اطلاع‌رسانی به جعبه dialog در مورد کلیک است. جعبه dialog پس از دریافت این اطلاع‌رسانی، تایید صحت را خودش انجام می‌دهد یا این وظیفه را به عناصر مجزا واگذار می‌کند. بنابراین، به جای وابستگی به ده‌ها عنصر فرم، دکمه تنها به کلاس باکس گفتگو وابسته است.

می‌توانید فراتر بروید و وابستگی را حتی سست‌تر کنید، با این کار که یک واسط مشترک برای تمام انواع جعبه‌های dialog تعریف کنید. این واسط، متد اطلاع‌رسانی را معرفی می‌کند که همه عناصر فرم می‌توانند از آن برای اطلاع‌رسانی به باکس گفتگو در مورد رویدادهای رخ‌داده در آن عناصر استفاده کنند. بنابراین، دکمه‌ی «ثبت» ما حالا باید بتواند با هر جعبه dialog که آن واسط را پیاده‌سازی می‌کند، کار کند.

به این ترتیب، الگوی طراحی واسطه به شما امکان می‌دهد تا یک شبکه‌ی پیچیده‌ی روابط بین اشیاء مختلف را درون یک شیء واسطه‌ی واحد کپسوله‌سازی کنید. هرچه وابستگی‌های یک کلاس کمتر باشد، اصلاح، توسعه یا استفاده‌ی مجدد از آن کلاس آسان‌تر می‌شود.

### 9.3.4.4- **تشبیه در دنیای واقعی**

![mediator-live-example](../../../assets/img/content/chapter9/designPatterns/mediator-live-example.png)

خلبانان هواپیماهایی که به منطقه‌ی کنترل فرودگاه نزدیک می‌شوند یا از آن خارج می‌شوند، به طور مستقیم با یکدیگر ارتباط برقرار نمی‌کنند. در عوض، آن‌ها با یک کنترل‌کننده‌ی ترافیک هوایی صحبت می‌کنند که در یک برج بلند، جایی در نزدیکی باند فرودگاه قرار دارد. بدون وجود کنترل‌کننده ترافیک هوایی، خلبانان باید از هر هواپیمایی در حوالی فرودگاه آگاه باشند و با یک کمیته‌ی متشکل از ده‌ها خلبان دیگر در مورد اولویت‌های فرود بحث کنند. این امر احتمالا آمار سقوط هواپیما را به طرز چشمگیری افزایش می‌داد.

برج نیازی به کنترل کل پرواز ندارد. برج فقط برای اعمال محدودیت‌ها در منطقه‌ی فرودگاه وجود دارد.

### 9.3.4.5- مثال

همانطور که می‌دانیم؛ الگوی طراحی Mediator یک الگوی طراحی رفتاری است. این الگو پیشنهاد می کند برای جلوگیری از ارتباط مستقیم بین اشیاء، یک شیء میانجی ایجاد شود تا وابستگی های مستقیم بین آنها از بین برود.

یک مثال بسیار خوب از الگوی Mediator، سکوی سیستم راه آهن است. دو قطار هرگز برای در دسترس بودن سکو با یکدیگر ارتباط برقرار نمی‌کنند. مسئول ایستگاه (stationManager) به عنوان میانجی (Mediator) عمل می کند و سکو را فقط برای یکی از قطارها در دسترس قرار می‌دهد. قطار با مسئول ایستگاه (**stationManager**) ارتباط برقرار می‌کند و بر اساس دستورات آن عمل می‌کند. این الگو صفی از قطارهای در انتظار را مدیریت می کند. در صورت خروج هر قطاری از سکو، به یکی از قطارها اطلاع می دهد که در ادامه به سکو برسد.

توجه کنید که چگونه stationManager در کد زیر به عنوان میانجی بین trains و platform عمل می کند.

- `passengerTrain` و `goodsTrain` رابط train را پیاده سازی می‌کنند.
- `stationManager` رابط mediator را پیاده سازی می‌کند.

### 9.3.4.6- مثال کاربردی


**train.go**

```go
package main

type train interface {
requestArrival()
departure()
permitArrival()
}
```


**passengerTrain.go**

```go
package main

import "fmt"

type passengerTrain struct {
mediator mediator
}

func (g *passengerTrain) requestArrival() {
if g.mediator.canLand(g) {
fmt.Println("PassengerTrain: Landing")
} else {
fmt.Println("PassengerTrain: Waiting")
}
}

func (g *passengerTrain) departure() {
fmt.Println("PassengerTrain: Leaving")
g.mediator.notifyFree()
}

func (g *passengerTrain) permitArrival() {
fmt.Println("PassengerTrain: Arrival Permitted. Landing")
}
```

**goodsTrain.go**


```go
package main

import "fmt"

type goodsTrain struct {
mediator mediator
}

func (g *goodsTrain) requestArrival() {
if g.mediator.canLand(g) {
fmt.Println("GoodsTrain: Landing")
} else {
fmt.Println("GoodsTrain: Waiting")
}
}

func (g *goodsTrain) departure() {
g.mediator.notifyFree()
fmt.Println("GoodsTrain: Leaving")
}

func (g *goodsTrain) permitArrival() {
fmt.Println("GoodsTrain: Arrival Permitted. Landing")
}
```



**mediator.go**


```go
package main

type mediator interface {
canLand(train) bool
notifyFree()
}
```


**stationManager.go**

```go
package main

import "sync"

type stationManager struct {
isPlatformFree bool
lock *sync.Mutex
trainQueue []train
}

func newStationManger() *stationManager {
return &stationManager{
isPlatformFree: true,
lock: &sync.Mutex{},
}
}

func (s *stationManager) canLand(t train) bool {
s.lock.Lock()
defer s.lock.Unlock()
if s.isPlatformFree {
s.isPlatformFree = false
return true
}
s.trainQueue = append(s.trainQueue, t)
return false
}

func (s *stationManager) notifyFree() {
s.lock.Lock()
defer s.lock.Unlock()
if !s.isPlatformFree {
s.isPlatformFree = true
}
if len(s.trainQueue) > 0 {
firstTrainInQueue := s.trainQueue[0]
s.trainQueue = s.trainQueue[1:]
firstTrainInQueue.permitArrival()
}
}
```


**main.go**

```go
package main

func main() {
stationManager := newStationManger()
passengerTrain := &passengerTrain{
mediator: stationManager,
}
goodsTrain := &goodsTrain{
mediator: stationManager,
}
passengerTrain.requestArrival()
goodsTrain.requestArrival()
passengerTrain.departure()
}
```


**Output:**

```go
PassengerTrain: Landing
GoodsTrain: Waiting
PassengerTrain: Leaving
GoodsTrain: Arrival Permitted. Landing
```



## **Full Working Code:**


```go
package main

import (
"fmt"
"sync"
)

type train interface {
requestArrival()
departure()
permitArrival()
}

type passengerTrain struct {
mediator mediator
}

func (g *passengerTrain) requestArrival() {
if g.mediator.canLand(g) {
fmt.Println("PassengerTrain: Landing")
} else {
fmt.Println("PassengerTrain: Waiting")
}
}

func (g *passengerTrain) departure() {
fmt.Println("PassengerTrain: Leaving")
g.mediator.notifyFree()
}

func (g *passengerTrain) permitArrival() {
fmt.Println("PassengerTrain: Arrival Permitted. Landing")
}

type goodsTrain struct {
mediator mediator
}

func (g *goodsTrain) requestArrival() {
if g.mediator.canLand(g) {
fmt.Println("GoodsTrain: Landing")
} else {
fmt.Println("GoodsTrain: Waiting")
}
}

func (g *goodsTrain) departure() {
g.mediator.notifyFree()
fmt.Println("GoodsTrain: Leaving")
}

func (g *goodsTrain) permitArrival() {
fmt.Println("GoodsTrain: Arrival Permitted. Landing")
}

type mediator interface {
canLand(train) bool
notifyFree()
}

type stationManager struct {
isPlatformFree bool
lock *sync.Mutex
trainQueue []train
}

func newStationManger() *stationManager {
return &stationManager{
isPlatformFree: true,
lock: &sync.Mutex{},
}
}

func (s *stationManager) canLand(t train) bool {
s.lock.Lock()
defer s.lock.Unlock()
if s.isPlatformFree {
s.isPlatformFree = false
return true
}
s.trainQueue = append(s.trainQueue, t)
return false
}

func (s *stationManager) notifyFree() {
s.lock.Lock()
defer s.lock.Unlock()
if !s.isPlatformFree {
s.isPlatformFree = true
}
if len(s.trainQueue) > 0 {
firstTrainInQueue := s.trainQueue[0]
s.trainQueue = s.trainQueue[1:]
firstTrainInQueue.permitArrival()
}
}

func main() {
stationManager := newStationManger()
passengerTrain := &passengerTrain{
mediator: stationManager,
}
goodsTrain := &goodsTrain{
mediator: stationManager,
}
passengerTrain.requestArrival()
goodsTrain.requestArrival()
passengerTrain.departure()
}
```

**Output:**

```go
PassengerTrain: Landing
GoodsTrain: Waiting
PassengerTrain: Leaving
GoodsTrain: Arrival Permitted. Landing
```


Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading