9.4.14.1 توضیحات #
الگوی Bridge Channel یکی از الگوهای ساده اما بسیار مفید در زبان Go است که امکان اتصال و انتقال داده بین دو یا چند کانال مستقل را فراهم میکند. این الگو زمانی کاربرد دارد که بخواهید دادههای تولیدشده در یک goroutine یا زیرسیستم را پس از دریافت، به کانال دیگری هدایت کنید؛ به عبارتی، مانند یک پل (bridge) عمل میکنید که دادهها را از یک کانال ورودی گرفته و به کانال خروجی منتقل مینماید.
در عمل، یک goroutine بین دو کانال قرار میگیرد: یکی برای دریافت (مثلاً in <-chan T
) و دیگری برای ارسال (out chan<- T
). این goroutine یک حلقه ساده for
با range in
اجرا میکند و هر مقداری که از کانال ورودی دریافت کند را بلافاصله به کانال خروجی میفرستد. این تکنیک برای decoupling بین تولیدکننده و مصرفکننده عالی است و در سناریوهایی مانند اتصال چند مرحله pipeline، تغییر مسیر دادهها، فیلترینگ دادهها یا حتی انتقال بین کانالهایی با ویژگیهای متفاوت (مثلاً بافر متفاوت یا ownership مختلف) بسیار کاربرد دارد.
از مزایای این الگو میتوان به سادگی در پیادهسازی، انعطافپذیری بالا، و جداسازی مسئولیتها اشاره کرد. این الگو به خصوص در سیستمهایی که نیاز به پردازش یا هدایت جریانهای داده بین چند بخش یا ماژول دارند، بسیار مؤثر است و به افزایش خوانایی و maintainability کد کمک میکند. در صورت نیاز میتوان عملیات اضافی مثل تبدیل داده، اعتبارسنجی یا لاگگیری را نیز داخل goroutine پل انجام داد تا ساختار تمیزتر باقی بماند.
9.4.14.2 دیاگرام #
9.4.17.3 نمونه کد #
1package main
2
3import (
4 "fmt"
5)
6
7// bridge بین input و output قرار میگیرد و دادهها را منتقل میکند.
8func bridge(input <-chan int, output chan<- int) {
9 for val := range input {
10 output <- val
11 }
12 close(output)
13}
14
15func main() {
16 input := make(chan int)
17 output := make(chan int)
18
19 // اجرای پل انتقال داده در یک goroutine جدا
20 go bridge(input, output)
21
22 // ارسال چند داده به کانال input
23 go func() {
24 for i := 1; i <= 3; i++ {
25 input <- i
26 }
27 close(input)
28 }()
29
30 // دریافت دادهها از کانال output
31 for val := range output {
32 fmt.Println("Received:", val)
33 }
34}
در این مثال، ما پیادهسازی بهبودیافتهای از الگوی Bridge Channel در زبان Go را مشاهده میکنیم؛ الگویی که هدف آن اتصال دو کانال (input و output) از طریق یک goroutine واسط (bridge) است. این واسط به صورت شفاف دادهها را از یک کانال میخواند و به کانال دیگری منتقل میکند، بهگونهای که بخشهای تولید (Producer) و مصرف (Consumer) بتوانند بدون وابستگی مستقیم به یکدیگر کار کنند.
در ابتدای برنامه، دو کانال input
و output
تعریف میشوند. سپس تابعی به نام bridge
ایجاد شده که به عنوان واسطه عمل میکند. این تابع در یک goroutine اجرا شده و با استفاده از یک حلقه for val := range input
، تا زمانی که کانال input
باز است، مقادیر را دریافت میکند و آنها را بلافاصله در کانال output
مینویسد. پس از بسته شدن input
، تابع bridge
نیز با بستن output
خاتمه مییابد؛ این یک الگوی بسیار ایمن و idiomatic در Go برای جلوگیری از goroutine leak است.
در بخش main
، یک goroutine دیگر وظیفه ارسال داده به input
را بر عهده دارد. در اینجا، مقادیر ۱ تا ۳ به input
ارسال شده و سپس کانال بسته میشود. در انتها، از یک حلقه for val := range output
استفاده شده تا دادههای منتقلشده به output
دریافت و چاپ شوند. این ساختار به گونهای طراحی شده که پس از اتمام پردازش، برنامه به صورت تمیز و بدون بلاک شدن به پایان میرسد.
این مدل نهتنها پایهای برای سیستمهای streaming و pipeline است، بلکه برای ساختاردهی بهتر به معماریهای همزمان، decoupling اجزا، و افزایش انعطافپذیری و توسعهپذیری کد بسیار مناسب است.
9.4.18.4 کاربردها #
- انتقال داده بین مراحل مختلف در خط لولههای داده
- اتصال میان دو زیرسیستم که از لحاظ طراحی جدا شدهاند
- بافر کردن بین تولیدکننده سریع و مصرفکننده کند (یا بالعکس)
- تغییر مسیر جریان دادهها (مثلاً برای logging یا debug)
- کنترل جریان بین سرویسهای مختلف در معماری microservice