86- آموزش جاوااسکریپت | Mediator Pattern
در این بخش با Mediator Pattern در JavaScript آشنا میشویم؛ الگویی برای مدیریت ارتباط بین آبجکتها از طریق یک واسطه مرکزی. همچنین با مثال عملی اتاق گفتوگو، نحوه ارسال پیام خصوصی و عمومی را بررسی میکنیم.
در این بخش، الگوی Mediator Pattern را بررسی میکنیم. این الگو یکی از Behavioral Patternها است و هدف آن، مدیریت ارتباط بین چند آبجکت از طریق یک واسطه مرکزی است.
بهجای اینکه آبجکتها مستقیماً با یکدیگر در ارتباط باشند، همه ارتباطات از طریق یک Mediator انجام میشود. این کار باعث میشود وابستگی بین اجزای مختلف برنامه کاهش پیدا کند و ساختار کد قابلمدیریتتر شود.
Mediator Pattern چیست؟
در Mediator Pattern، یک آبجکت مرکزی به نام Mediator مسئول هماهنگی ارتباط بین چند آبجکت دیگر است. این آبجکتهای دیگر معمولاً Colleague نامیده میشوند.
در این الگو:
- Mediator مسئول برقراری ارتباط است
- Colleagueها بهجای ارتباط مستقیم با هم، از طریق Mediator پیام ردوبدل میکنند
- وابستگی بین اجزا کمتر میشود
- تغییر یا توسعه سیستم آسانتر خواهد شد
مثال کاربردی: اتاق گفتوگو
یکی از بهترین مثالها برای Mediator Pattern، یک Chat Room یا اتاق گفتوگو است.
در این مثال:
- هر کاربر یک colleague است
- اتاق گفتوگو نقش mediator را دارد
- کاربران میتوانند:
- به یک کاربر خاص پیام بدهند
- یا پیام را برای همه کاربران ارسال کنند
ساختار کلی مثال
در این پیادهسازی، دو سازنده اصلی داریم:
UserChatroom
کلاس User نماینده کاربران است و Chatroom نقش واسطه را بر عهده دارد.
تعریف سازنده User
ابتدا سازنده مربوط به کاربر را تعریف میکنیم:
const User = function (name) {
this.name = name;
this.chatroom = null;
};
در اینجا:
nameنام کاربر را نگه میداردchatroomدر ابتداnullاست، چون کاربر هنوز در هیچ اتاقی ثبت نشده است
تعریف سازنده Chatroom
اکنون سازنده اتاق گفتوگو را میسازیم:
const Chatroom = function () {
this.users = {};
};
در اینجا، ویژگی users یک آبجکت خالی است که لیست کاربران ثبتشده در اتاق را نگه میدارد.
تعریف متدهای User
برای کاربران دو متد اصلی تعریف میکنیم:
sendreceive
User.prototype = {
send: function (message, to) {
this.chatroom.send(message, this, to);
},
receive: function (message, from) {
console.log(`${from.name} to ${this.name}: ${message}`);
}
};
بررسی متدهای User
متد send
این متد مستقیماً به کاربر دیگر پیام نمیفرستد.
بهجای آن، پیام را به chatroom میدهد تا mediator تصمیم بگیرد پیام باید به چه کسی برسد.
send: function (message, to) {
this.chatroom.send(message, this, to);
}
متد receive
این متد زمانی اجرا میشود که کاربر پیامی دریافت کند:
receive: function (message, from) {
console.log(`${from.name} to ${this.name}: ${message}`);
}
تعریف متدهای Chatroom
اکنون نوبت به تعریف منطق mediator میرسد. اتاق گفتوگو باید بتواند:
- کاربران را ثبت کند
- پیام خصوصی ارسال کند
- پیام عمومی برای همه کاربران بفرستد
Chatroom.prototype = {
register: function (user) {
this.users[user.name] = user;
user.chatroom = this;
},
send: function (message, from, to) {
if (to) {
to.receive(message, from);
} else {
for (let key in this.users) {
if (this.users[key] !== from) {
this.users[key].receive(message, from);
}
}
}
}
};
بررسی متدهای Chatroom
متد register
این متد یک کاربر را در اتاق ثبت میکند:
register: function (user) {
this.users[user.name] = user;
user.chatroom = this;
}
در این متد:
- کاربر با کلید
nameدر لیست کاربران ذخیره میشود - مرجع
chatroomکاربر به اتاق فعلی اختصاص داده میشود
متد send
این متد مسئول ارسال پیام است:
send: function (message, from, to) {
if (to) {
to.receive(message, from);
} else {
for (let key in this.users) {
if (this.users[key] !== from) {
this.users[key].receive(message, from);
}
}
}
}
منطق این متد به دو حالت تقسیم میشود:
1. ارسال پیام خصوصی
اگر مقدار to وجود داشته باشد، پیام فقط به همان کاربر ارسال میشود:
to.receive(message, from);
2. ارسال پیام عمومی
اگر to مشخص نشده باشد، پیام برای همه کاربران اتاق ارسال میشود، بهجز فرستنده:
for (let key in this.users) {
if (this.users[key] !== from) {
this.users[key].receive(message, from);
}
}
ساخت کاربران و اتاق گفتوگو
اکنون چند کاربر و یک chatroom میسازیم:
const brad = new User('Brad');
const jeff = new User('Jeff');
const sarah = new User('Sarah');
const chatroom = new Chatroom();
ثبت کاربران در Chatroom
قبل از ارسال پیام، کاربران باید در اتاق ثبت شوند:
chatroom.register(brad);
chatroom.register(jeff);
chatroom.register(sarah);
ارسال پیام خصوصی
اکنون میتوانیم بین کاربران پیام خصوصی ارسال کنیم:
brad.send('Hello Jeff', jeff);
sarah.send('Hello Brad, you are the best dev ever', brad);
خروجی این بخش بهصورت مفهومی چنین خواهد بود:
Brad to Jeff: Hello Jeff
Sarah to Brad: Hello Brad, you are the best dev ever
ارسال پیام عمومی
اگر پارامتر to را ارسال نکنیم، پیام برای همه کاربران اتاق فرستاده میشود:
jeff.send('Hello everyone');
خروجی:
Jeff to Brad: Hello everyone
Jeff to Sarah: Hello everyone
توجه کنید که پیام برای خود Jeff ارسال نمیشود، چون در منطق برنامه فرستنده از لیست دریافتکنندگان حذف شده است.
نسخه کامل مثال
در ادامه، کل کد را یکجا میبینید:
const User = function (name) {
this.name = name;
this.chatroom = null;
};
const Chatroom = function () {
this.users = {};
};
User.prototype = {
send: function (message, to) {
this.chatroom.send(message, this, to);
},
receive: function (message, from) {
console.log(`${from.name} to ${this.name}: ${message}`);
}
};
Chatroom.prototype = {
register: function (user) {
this.users[user.name] = user;
user.chatroom = this;
},
send: function (message, from, to) {
if (to) {
to.receive(message, from);
} else {
for (let key in this.users) {
if (this.users[key] !== from) {
this.users[key].receive(message, from);
}
}
}
}
};
const brad = new User('Brad');
const jeff = new User('Jeff');
const sarah = new User('Sarah');
const chatroom = new Chatroom();
chatroom.register(brad);
chatroom.register(jeff);
chatroom.register(sarah);
brad.send('Hello Jeff', jeff);
sarah.send('Hello Brad, you are the best dev ever', brad);
jeff.send('Hello everyone');
چرا Mediator Pattern مفید است؟
اگر آبجکتها مستقیماً با یکدیگر در ارتباط باشند، وابستگی زیادی بین آنها ایجاد میشود. این موضوع در پروژههای بزرگ باعث پیچیدگی و سختتر شدن نگهداری کد میشود.
Mediator Pattern این مشکل را حل میکند، چون:
- ارتباطها را متمرکز میکند
- وابستگی مستقیم بین آبجکتها را کاهش میدهد
- توسعه و تغییر رفتار سیستم را آسانتر میکند
- ساختار برنامه را تمیزتر و قابلفهمتر میسازد
کاربردهای رایج Mediator Pattern
این الگو در سناریوهای مختلفی کاربرد دارد، از جمله:
- سیستمهای گفتوگو و پیامرسانی
- ارتباط بین اجزای رابط کاربری
- هماهنگی بین ماژولهای مستقل
- مدیریت eventها در ساختارهای پیچیده
- سیستمهایی که چند شیء باید از طریق یک مرکز مشترک با هم ارتباط داشته باشند
نکته مهم درباره استفاده از Class
در این مثال، پیادهسازی با prototype انجام شده است. همین ساختار را میتوان با ES6 class نیز نوشت. از نظر مفهومی تفاوتی وجود ندارد و فقط syntax تغییر میکند.
اگر با class راحتتر هستید، میتوانید همین الگو را بهصورت class-based هم پیادهسازی کنید. با این حال، درک نسخه prototype به فهم بهتر مدل شیءگرایی JavaScript کمک میکند.
جمعبندی
در this بخش با Mediator Pattern در JavaScript آشنا شدیم. این الگو برای مدیریت ارتباط بین آبجکتها از طریق یک واسطه مرکزی استفاده میشود و به کاهش وابستگی مستقیم بین اجزا کمک میکند.
در مثال chat room دیدیم که:
- کاربران مستقیماً با هم ارتباط ندارند
- همه پیامها از طریق
Chatroomمدیریت میشوند - امکان ارسال پیام خصوصی و عمومی وجود دارد
اگر در پروژهای با چند آبجکت در تعامل روبهرو هستید و میخواهید ساختار ارتباط آنها منظمتر و قابلمدیریتتر باشد، Mediator Pattern میتواند انتخاب بسیار خوبی باشد.