মূল বিষয়বস্তুতে যান
Clean Code Mastery

Mediator Pattern: Control Tower যেটা ক্যাওস থামায়

বিমানবন্দরের control tower-এর গল্প দিয়ে Mediator pattern শেখো — সহজ TypeScript আর C# কোড, MediatR উদাহরণ, diagram, table আর practice task সহ।

23 মিনিট আপডেট: June 11, 2026beginner
design-patternsbehavioral-patternsmediatortypescriptcsharpmediatrloose-coupling

ঢাকা বিমানবন্দরে এক ব্যস্ত সন্ধ্যা 🛫

ধরো সন্ধ্যা ৭টা। হযরত শাহজালাল আন্তর্জাতিক বিমানবন্দর, ঢাকা। বর্ষার মেঘ ভারী। বিমানবন্দরের উপরের আকাশ ভরা জ্বলতে-নিভতে থাকা আলো — প্রতিটা আলো একটা বিমান, ভেতরে শত শত মানুষ।

এই পুরো post-এর চরিত্রদের সাথে পরিচয় করিয়ে দিই। নামগুলো মনে রাখো, কারণ এরা শেষ পর্যন্ত আমাদের সাথে থাকবে।

  • ক্যাপ্টেন রাহেলা উড়ছেন বিমান বাংলাদেশ BG-202-তে, চট্টগ্রাম থেকে আসছেন। জ্বালানি কমে আসছে। নামতে চান।
  • ক্যাপ্টেন জামাল Air Astra KM-145-এ মাটিতে বসে আছেন, engine গরম, সিলেটের উদ্দেশ্যে রওনা দেওয়ার জন্য তৈরি।
  • ক্যাপ্টেন নাসরিন US-Bangla BS-995-এ উপরে চক্কর দিচ্ছেন, তার পালার অপেক্ষায়।
  • আর উঁচু কাঁচের tower-এ বসে আছেন তারিক — air traffic controller, radar screen, headset আর খুব শান্ত একটা গলা নিয়ে।

এবার একটু ভাবো। তিনটা বিমান, একটা runway। কে আগে যাবে?

কল্পনা করো কোনো tower নেই। রাহেলাকে জামালকে radio-তে ডাকতে হবে: "জামাল ভাই, আপনি কি এখন উড়ছেন নাকি আমি নামতে পারি?" জামালকে নাসরিনকে ডাকতে হবে: "নাসরিন আপা, জ্বালানি কতটুকু আছে? পাঁচ মিনিট অপেক্ষা করতে পারবেন?" নাসরিনকে রাহেলাকে ডাকতে হবে। প্রতিটা পাইলট প্রতিটা পাইলটের সাথে কথা বলছে, একই সময়ে, অন্ধকারে, বৃষ্টিতে। একটা call miss, একটা ভুল অনুমান — আর দুটো বিমান একই runway-তে দেখা করতে পারে। সেই শব্দটা লিখতেও ভয় লাগে।

বাস্তব জীবনে এটা কখনো হয় না। কেন? তারিকের জন্য।

প্রতিটা পাইলট শুধু তারিকের সাথে কথা বলে। তারিক radar-এ পুরো আকাশ দেখেন। তিনি বলেন, "বিমান BG-202, আপনি runway ২৯-এ নামতে পারেন।" তিনি বলেন, "Air Astra KM-145, দুই মিনিট অবস্থানে থাকুন।" তিনি বলেন, "US-Bangla BS-995, ৩০০০ ফুটে থাকুন, নামার সিরিয়ালে আপনি দ্বিতীয়।" রাহেলা কখনো জামালের সাথে কথা বলেন না। জামাল কখনো নাসরিনের সাথে কথা বলেন না। প্রতিটা পাইলটের একটাই conversation — tower-এর সাথে। আর যেন জাদুর মতো, পুরো আকাশ সুশৃঙ্খল থাকে।

এটাই হলো Mediator pattern, একদম হুবহু। Tower হলো mediator। বিমানগুলো হলো components। বিমানগুলো একে অপরের সাথে কথা বলে না। তারা শুধু tower-এর সাথে কথা বলে, আর tower সব কিছু coordinate করে।

এই post-এ আমরা তারিকের tower তিনটা ভাষায় তিনবার code-এ বানাবো। Wire গুলো গণনা করবো, ছবি দেখবো, আর শেষে তুমি জানবে ঠিক কখন নিজের program-এ একটা control tower বানাতে হবে — আর কখন হবে না।

Mediator Pattern মানে কী?

সহজ সংজ্ঞাটা এরকম।

Mediator হলো একটা behavioral design pattern যেটা একদল object-কে সরাসরি একে অপরের সাথে কথা বলা থেকে বিরত রাখে। এর বদলে সবাই একটা central object-এর সাথে কথা বলে — mediator — আর mediator ঠিক করে পরবর্তীতে কে কী করবে।

সংযোগের আকৃতিটা নিয়ে একটু ভাবো। Mediator ছাড়া, প্রতিটা object প্রতিটা অন্য object-এর সাথে সংযুক্ত থাকতে পারে। দেখতে এলোমেলো মাকড়সার জালের মতো। Mediator দিয়ে, প্রতিটা object-এর শুধু একটা সংযোগ থাকে — mediator-এর সাথে। দেখতে একটা গোছানো তারার মতো, মাঝখানে mediator জ্বলজ্বল করছে।

"Mediator" শব্দটার মানেই হলো "মাঝখানে যে ব্যক্তি দুই পক্ষকে কথা বলতে সাহায্য করে"। বাংলাদেশের পরিবারে, যখন দুই আত্মীয় একে অপরের সাথে কথা বলছে না, তখন প্রায়ই এক জ্ঞানী চাচা প্রতিটা অনুষ্ঠানে চুপিচুপি বার্তা পাঠান। সেই চাচাও একজন mediator। তিনি বার্তা বহন করেন, কথার ধার কমান, আর ঠিক করেন কী পাঠাবেন আর কী বাদ দেবেন।

💡

সহজ মনে রাখার কৌশল: Mediator = Control Tower। Components হলো বিমান। বিমান কখনো বিমানকে ডাকে না। বিমান tower-কে ডাকে, আর tower বিমানকে ডাকে। তারিককে তার কাঁচের tower-এ মনে রাখলেই pattern মনে থাকবে।

Pattern-এর চারটা অংশ আছে। এই তালিকাটা হাতের কাছে রাখো:

  1. Mediator interface — একটা ছোট contract, সাধারণত একটাই method থাকে যেমন notify(sender, event)। এটা হলো "radio frequency" যেটায় সবাই agree করেছে।
  2. Concrete Mediator — আসল control tower। এটা সব components-এর reference ধরে রাখে আর সব coordination rule এখানে থাকে। তারিক তার radar নিয়ে।
  3. Base Component — প্রতিটা component mediator-এর একটা reference রাখে। প্রতিটা বিমানের radio tower-এ tune করা আছে।
  4. Concrete Components — বিমানগুলো নিজেরাই। তারা তাদের নিজেদের ছোট কাজ করে (উড়তে থাকা!) আর mediator-কে events জানায়। তারা একে অপরের সম্পর্কে কিছুই জানে না।

সমস্যাটা কী ছিল: জট পাকানো আকাশ

আগে ব্যথাটা অনুভব করি। ধরো airport code "naive" উপায়ে লিখলাম, যেখানে প্রতিটা flight প্রতিটা অন্য flight সম্পর্কে জানে।

// ❌ BAD: every flight knows about other flights directly
class Flight {
  constructor(public name: string) {}
 
  otherFlights: Flight[] = [];
  isLandingNow = false;
 
  requestLanding() {
    // This flight must personally ask EVERY other flight!
    for (const other of this.otherFlights) {
      if (other.isLandingNow) {
        console.log(`${this.name}: Oh no, ${other.name} is landing. I must wait.`);
        return;
      }
    }
    console.log(`${this.name}: Nobody told me to stop, so I am landing!`);
  }
}

এখানে কী ভুল আছে? অনেক কিছু, আর প্রতিটাই একটা বাস্তব bug যেটা ঘটার অপেক্ষায় আছে।

  • প্রতিটা flight-কে অন্য সব flight-এর list রাখতে হবে। নতুন একটা flight আকাশে এলে সব existing flight update করতে হবে। এটা যেন প্রতিটা পাইলটকে মাঝ-আকাশে পঞ্চাশজন অন্য পাইলটের ফোন নম্বর লিখে নিতে হচ্ছে।
  • Rules ছড়িয়ে-ছিটিয়ে আছে। "একটাই বিমান runway ব্যবহার করতে পারবে" — এই নিয়মটা Flight class-এর ভেতরে লুকিয়ে আছে। আগামীকাল দ্বিতীয় runway যোগ করলে প্রতিটা flight edit করতে হবে। VIP priority rule যোগ করলে, আবার প্রতিটা flight।
  • কিছুই reusable না। যে Flight এই নির্দিষ্ট অন্য flights সম্পর্কে জানে, সেটা চট্টগ্রাম বিমানবন্দরে ব্যবহার করা যাবে না। এটা ঢাকার সাথে আটকে আছে।
  • নিয়ন্ত্রণের বাইরে বাড়তে থাকে। বিমান বাড়লে connections বহুগুণে বাড়ে। একটু পরেই আসল সংখ্যা দিয়ে এই বিস্ফোরণ দেখবো।

দুটো আকৃতি পাশাপাশি দেখো। বাম দিকে জঞ্জাল। ডান দিকে তারা।

চিত্র ১: Mediator ছাড়া চারটা বিমানের জন্য ছয়টা wire লাগে। Tower দিয়ে চারটা বিমানের জন্য মাত্র চারটা wire — প্রতিটার জন্য একটা।

নিজে line গণনা করো। বাম দিকের জালে মাত্র ৪টা বিমানের জন্য ৬টা wire। ডান দিকের তারায় মাত্র ৪টা wire — প্রতিটা বিমানের জন্য একটা — rules যত জটিলই হোক। সব জটিল rules এখন একটা পাঠযোগ্য জায়গায়: tower-এ।

কলেজ কর্নার: এখানে সঠিক গণিত। nটা components-এর সিস্টেমে যেখানে যে কেউ যে কারো সাথে কথা বলতে পারে, সেই communication graph হলো complete graph। Complete graph-এ undirected edge-এর সংখ্যা হলো n(n-1)/2। ৪টা বিমানের জন্য সেটা 4 × 3 / 2 = 6। ১০টা বিমানের জন্য ৪৫। ৫০টার জন্য ১,২২৫। বৃদ্ধিটা quadratic — Big-O-তে O(n²) possible communication paths, আর O(n²) জায়গা যেখানে একটা rule লুকিয়ে থাকতে পারে। Mediator এই complete graph-কে star graph-এ রূপান্তরিত করে, যেটায় ঠিক nটা edge থাকে — linear, O(n)। সমস্যা অদৃশ্য হয়নি; topology পরিবর্তন হয়েছে "সবাই সবার সাথে সংযুক্ত" থেকে "সবাই একটা hub-এর সাথে সংযুক্ত"-এ। এই একটা পরিবর্তনই কারণ pattern-টা scale করে।

Wire-এর হিসাব 📈

সংখ্যা কথার চেয়ে বেশি convince করে। আকাশ ব্যস্ত হলে wire-এর হিসাব এরকম:

আকাশে বিমানMediator ছাড়া wire n(n-1)/2Mediator দিয়ে wire nসাশ্রয়
3330
51055
828820
12661254
501,225501,175

প্রথম সারিটা লক্ষ্য করো। ৩টা বিমানে mediator কিছুই বাঁচায় না — দুটো আকৃতিতেই ৩টা wire লাগে। এটা সৎ আর গুরুত্বপূর্ণ একটা বিষয়: mediator তখনই লাভজনক হয় যখন দল বাড়ে। ছোট সিস্টেমের জন্য এটা বাড়তি ঝামেলা।

এখন দুটো curve-কে দৌড়াতে দেখো:

চিত্র ২: Direct connections quadratically বাড়ে; mediator connections সোজা, শান্ত line-এ বাড়ে।

উপরের curve হলো মাকড়সার জাল। নিচের line হলো তারিকের তারা। ১২টা বিমানে জালে ৬৬টা wire লাগে আর তারায় লাগে ১২টা। প্রতিটা বাড়তি wire হলো একটা জায়গা যেখানে একটা bug মাসের পর মাস চুপচাপ বসে থাকতে পারে।

আর এই বিস্ফোরণ বিমানবন্দর থেকে অনেক দূরে, দৈনন্দিন code-এও দেখা যায়। ধরো একটা sign-up form। "country" dropdown-টা PIN code field পুনরায় check করবে। "অন্য ঠিকানায় পাঠাও" checkbox-টা একটা লুকানো address box দেখাবে। Submit button-টা সব কিছু valid না হওয়া পর্যন্ত disabled থাকবে। প্রতিটা widget যদি অন্য widget-গুলোকে সরাসরি ধাক্কা দেয়, তুমি একই মাকড়সার জাল পাবে, শুধু ছোট। Mediator হিসেবে কাজ করা একটা form dialog এটা ঠিক করে ঠিক যেভাবে tower আকাশ ঠিক করে।

একটা Landing ধাপে ধাপে কীভাবে হয়

এখানে recipe। Pattern apply করার সময় প্রতিবার এই ছয়টা ধাপ follow করো।

  1. জঞ্জাল খোঁজো। এমন objects-এর দল খোঁজো যেগুলো অনেক দিক থেকে একে অপরকে সরাসরি call করছে — form widget, chat user, বিমান।
  2. Mediator interface declare করো। সাধারণত একটা method-ই যথেষ্ট: notify(sender, event)। Sender বলে কে কথা বলছে; event বলে কী হয়েছে
  3. Concrete mediator বানাও। এটাকে সে manage করা সব components-এর দিকে নির্দেশ করা fields দাও। প্রায়ই mediator নিজেই ওই components তৈরি করে।
  4. প্রতিটা component-কে একটা mediator reference দাও। Constructor-এ বা setter দিয়ে pass করো। Components শুধুমাত্র ছোট mediator interface-এর উপর depend করবে।
  5. Direct call-এর বদলে notification দাও। যেখানে component A একসময় component B-তে হাত দিত, A এখন শুধু বলে mediator.notify(this, "something happened")
  6. সব coordination logic mediator-এর ভেতরে রাখো। এর notify method sender আর event দেখে, তারপর সঠিক components-কে command দেয়।

এখন রাহেলার landing request সিস্টেমের মধ্যে দিয়ে যাওয়া দেখো, message by message:

চিত্র ৩: একটা landing request tower-এর মধ্যে দিয়ে যায়। রাহেলা আর জামাল কখনো একটাও message আদান-প্রদান করে না।

সুন্দর জিনিসটা লক্ষ্য করো: রাহেলা জামালকে একটাও message পাঠায় না। Tower receive করে, ভাবে, আর command দেয়। আগামীকাল আরো বিশটা বিমান যোগ করলেও রাহেলার cockpit procedures মোটেও বদলাবে না। সে ঠিক দুটো কাজ করে: tower-কে জিজ্ঞেস করা, tower-এর কথা মানা।

আর এখানে মানুষের দৃষ্টিকোণ থেকে একই সন্ধ্যা — শুধু messages না, অনুভূতিগুলোও:

চিত্র ৪: ঢাকা বিমানবন্দরে এক বৃষ্টির সন্ধ্যা, একটা যাত্রা হিসেবে। Tower আতঙ্ককে শান্তিতে পরিণত করে।

মাঝখানে জামালের score ৩ লক্ষ্য করো। "অবস্থানে থাকুন" বলাটা একটু বিরক্তিকর — এটা সৎ। Mediator সবাইকে তাৎক্ষণিকভাবে খুশি করে না; এটা সবাইকে নিরাপদ আর coordinated রাখে, যেটা অনেক বেশি গুরুত্বপূর্ণ।

Blueprint 📐

পুরো program লেখার আগে, এখানে class structure আছে যেটা প্রতিটা Mediator implementation follow করে। এই diagram-টাই তুমি পরীক্ষায় আর interview-তে আঁকবে:

চিত্র ৫: Mediator class structure — components শুধু ছোট interface-কে নির্দেশ করে, কখনো একে অপরকে না।

Arrow-গুলো মনোযোগ দিয়ে পড়ো। Flight concrete DelhiTower-কে না, interface ControlTower-কে নির্দেশ করে। মানে আগামীকাল সম্পূর্ণ ভিন্ন rules সহ একটা ChittagongTower swap in করতে পারবে, আর Flight class মোটেও টের পাবে না। এদিকে DelhiTower flights-এর দিকে নির্দেশ করে যাতে সে সেগুলোকে command দিতে পারে। Flight থেকে Flight-এ কোনো arrow নেই। এই missing arrow-টাই হলো পুরো pattern।

Tower-এর দৃষ্টিকোণ থেকে প্রতিটা বিমান একটা ছোট states-এর set-এর মধ্যে দিয়ে যায়। Tower-এর কাজ আসলে এই state changes নিরাপদে manage করা:

চিত্র ৬: Tower যেভাবে একটা বিমানকে দেখে তার জীবন। শুধু tower-ই বিমানকে states-এর মধ্যে সরায়।

একটা বিমান নিজে থেকে Holding থেকে Landing-এ যায় না। শুধু tower-এর instruction-ই সেটা করে। Code-এর ভাষায়: একটা component নিজে থেকে shared state পরিবর্তন করে না; সে mediator-কে জিজ্ঞেস করে, আর mediator state পরিবর্তন করে।

আসল Code: TypeScript-এ তারিকের Tower বানাই

এখন ঢাকা বিমানবন্দর ঠিকমতো বানাই, Mediator pattern দিয়ে। Comments পড়ো — সেগুলোই গল্প বলে।

// --- Step 1: The Mediator interface (the radio frequency) ---
interface ControlTower {
  notify(sender: Flight, event: string): void;
}
 
// --- Step 2: The Component ---
// Every flight knows ONLY the tower. Never another flight.
class Flight {
  constructor(
    public readonly name: string,
    private tower: ControlTower
  ) {}
 
  // The pilot presses a button: "I want to land."
  requestLanding(): void {
    console.log(`${this.name} (pilot): Tower, requesting permission to land.`);
    this.tower.notify(this, "request-landing");
  }
 
  // The tower may call these methods on the flight:
  land(): void {
    console.log(`${this.name}: Landing now. Touchdown! 🛬`);
    this.tower.notify(this, "landed");
  }
 
  hold(): void {
    console.log(`${this.name}: Holding in the air, circling patiently.`);
  }
}
 
// --- Step 3: The Concrete Mediator (Vikram in the Delhi tower) ---
class DelhiTower implements ControlTower {
  private runwayFree = true;           // only the tower knows the runway state
  private waitingQueue: Flight[] = []; // only the tower manages the queue
 
  notify(sender: Flight, event: string): void {
    if (event === "request-landing") {
      if (this.runwayFree) {
        this.runwayFree = false;
        console.log(`Tower: ${sender.name}, you are cleared to land on runway 29.`);
        sender.land();
      } else {
        console.log(`Tower: ${sender.name}, runway busy. Hold at 3000 feet.`);
        this.waitingQueue.push(sender);
        sender.hold();
      }
    }
 
    if (event === "landed") {
      console.log(`Tower: ${sender.name} has landed safely. Runway is free.`);
      this.runwayFree = true;
 
      // The tower decides who goes next. The flights never argue.
      const next = this.waitingQueue.shift();
      if (next) {
        console.log(`Tower: ${next.name}, your turn now.`);
        next.requestLanding();
      }
    }
  }
}
 
// --- Step 4: Wire everything and run the rainy evening ---
const tower = new DelhiTower();
 
const meera = new Flight("IndiGo 6E-202", tower);
const arjun = new Flight("Air India 145", tower);
const divya = new Flight("Vistara UK-995", tower);
 
meera.requestLanding();
arjun.requestLanding();
divya.requestLanding();

এটা run করো, আর output পুরো airport-এর নাটক বলে দেয়:

IndiGo 6E-202 (pilot): Tower, requesting permission to land.
Tower: IndiGo 6E-202, you are cleared to land on runway 29.
IndiGo 6E-202: Landing now. Touchdown! 🛬
Tower: IndiGo 6E-202 has landed safely. Runway is free.
Air India 145 (pilot): Tower, requesting permission to land.
Tower: Air India 145, you are cleared to land on runway 29.
Air India 145: Landing now. Touchdown! 🛬
Tower: Air India 145 has landed safely. Runway is free.
Vistara UK-995 (pilot): Tower, requesting permission to land.
Tower: Vistara UK-995, you are cleared to land on runway 29.
Vistara UK-995: Landing now. Touchdown! 🛬
Tower: Vistara UK-995 has landed safely. Runway is free.

তিনটা জিনিস দেখো:

  1. Flight class-এ অন্য flights-এর শূন্যটা reference আছে। আগামীকাল সকালে এটা copy-paste করে চট্টগ্রাম airport project-এ ব্যবহার করতে পারবে।
  2. সব rules — runway status, waiting queue, কে পরবর্তী — একটা class-এ বসে আছে, DelhiTower-এ। পুরো "traffic protocol" ত্রিশ সেকেন্ডে উপর থেকে নিচ পর্যন্ত পড়তে পারবে।
  3. দ্বিতীয় runway চাই? শুধু tower edit করো। রাহেলার মতো কম জ্বালানির বিমানের জন্য VIP priority queue চাই? শুধু tower। Flights কখনো বদলায় না।

C#-এ একই ধারণা — আর বিখ্যাত MediatR Library

C# developers প্রতিদিন এই pattern ব্যবহার করেন, প্রায়ই MediatR নামের একটা library-র মাধ্যমে। কিন্তু আগে plain pattern, সংক্ষিপ্তভাবে:

// The mediator contract
public interface IControlTower
{
    void Notify(Flight sender, string evt);
}
 
// The component — knows only the tower
public class Flight
{
    private readonly IControlTower _tower;
    public string Name { get; }
 
    public Flight(string name, IControlTower tower)
    {
        Name = name;
        _tower = tower;
    }
 
    public void RequestLanding()
    {
        Console.WriteLine($"{Name}: Tower, requesting landing.");
        _tower.Notify(this, "request-landing");
    }
 
    public void Land() => Console.WriteLine($"{Name}: Landing. Touchdown!");
    public void Hold() => Console.WriteLine($"{Name}: Holding position.");
}
 
// The concrete mediator
public class DelhiTower : IControlTower
{
    private bool _runwayFree = true;
    private readonly Queue<Flight> _waiting = new();
 
    public void Notify(Flight sender, string evt)
    {
        if (evt == "request-landing" && _runwayFree)
        {
            _runwayFree = false;
            Console.WriteLine($"Tower: {sender.Name}, cleared to land.");
            sender.Land();
            _runwayFree = true;
            if (_waiting.Count > 0) Notify(_waiting.Dequeue(), "request-landing");
        }
        else if (evt == "request-landing")
        {
            Console.WriteLine($"Tower: {sender.Name}, hold position.");
            _waiting.Enqueue(sender);
            sender.Hold();
        }
    }
}

বাস্তব .NET project-এ, Jimmy Bogard-এর MediatR library একই idea পুরো application-এ apply করে। একটা web controller সরাসরি service class call করে না। সে mediator-এ একটা request object পাঠায়, আর mediator সেই একটা handler খুঁজে বের করে যেটা কী করতে হবে সেটা জানে:

// The controller does not know WHO will handle this. Only the mediator knows.
var result = await _mediator.Send(new BookFlightCommand("Delhi", "Chennai"));

Controller আর handler কখনো দেখা করে না। তারা দুজন পাইলটের মতো যারা শুধু tower চেনে। এই কারণেই MediatR সমগ্র .NET world-এ সবচেয়ে বেশি download হওয়া packages-এর একটা হয়ে উঠেছে, বিশেষত CQRS design-এ যেখানে commands আর queries mediator-এর মধ্যে দিয়ে তাদের handlers-এ যায়, controllers পাতলা আর পরিষ্কার রাখে।

আর set সম্পূর্ণ করতে, এখানে Python-এ pattern-এর মূল অংশ — লক্ষ্য করো ভাষা বদলালেও আকৃতি একই থাকে:

# The mediator owns the rules; the flights own only their radios.
class DelhiTower:
    def __init__(self):
        self.runway_free = True
        self.waiting = []
 
    def notify(self, sender, event):
        if event == "request-landing":
            if self.runway_free:
                self.runway_free = False
                print(f"Tower: {sender.name}, cleared to land.")
                sender.land()
            else:
                print(f"Tower: {sender.name}, hold position.")
                self.waiting.append(sender)
        elif event == "landed":
            self.runway_free = True
            if self.waiting:
                self.notify(self.waiting.pop(0), "request-landing")
 
 
class Flight:
    def __init__(self, name, tower):
        self.name = name
        self.tower = tower   # the ONLY reference a flight holds
 
    def request_landing(self):
        print(f"{self.name}: Tower, requesting landing.")
        self.tower.notify(self, "request-landing")
 
    def land(self):
        print(f"{self.name}: Touchdown!")
        self.tower.notify(self, "landed")
 
 
tower = DelhiTower()
meera = Flight("IndiGo 6E-202", tower)
arjun = Flight("Air India 145", tower)
meera.request_landing()
arjun.request_landing()

তিনটা ভাষা, একটা আকৃতি: components একটাই reference ধরে, mediator brain ধরে।

Logic কোথায় থাকে? 🧠

ছাত্রছাত্রীরা একটা প্রশ্ন করে: "জটিলতা কি আসলে কমল, নাকি শুধু সরে গেল?" সৎ উত্তর হলো: এটা সরল আর একত্রিত হলো — আর সেটাই জয়। বিশটা file-এ ছড়িয়ে-ছিটিয়ে থাকা logic ঠিক করা যায় না; একটা file-এ concentrated logic পড়া যায়। Pattern apply করার পর coordination knowledge মোটামুটি এখানে থাকে:

চিত্র ৭: Pattern-এর পরে, প্রায় সব coordination rules tower-এর ভেতরে থাকে, যেখানে একজন মানুষ পড়তে পারবে।

৮০ শতাংশ slice-টাই হলো মূল বিষয়। Pattern-এর আগে, একই ৮০ শতাংশ প্রতিটা plane class-এ ছড়িয়ে ছিল, duplicate আর প্রতিটায় একটু আলাদা। এখন তারিকের notebook সব কিছু ধরে রেখেছে।

কলেজ কর্নার: এই concentration হলো system level-এ Single Responsibility Principle apply করা। প্রতিটা Flight-এর পরিবর্তনের একটাই কারণ: flying behaviour। DelhiTower-এর পরিবর্তনের একটাই কারণ: coordination policy। এটাকে naive design-এর সাথে তুলনা করো — সেখানে একটা policy যোগ করা ("কম জ্বালানির বিমান queue-তে আগে যাবে") nটা component class-এ edit করতে বাধ্য করত। Mediator দিয়ে, প্রতিটা policy change O(1) class touch করে। যে trade-off তুমি নিচ্ছ সেটা হলো hub-এ complexity-র একটা single point।

এখানে ব্যবহার করবে কিনা? একটা Decision ছবি

সব project-এ tower লাগে না। দিনে একবার উড়া দুটো বিমান জানালা দিয়ে দেখতেই পারে। নিজের পরিস্থিতি রাখতে এই quadrant ব্যবহার করো:

চিত্র ৮: অনেক components-এর জটিল cross-talk-এ Mediator উজ্জ্বল। ছোট সহজ সিস্টেমে, skip করো।

আর দশ সেকেন্ডে scan করা যাবে এমন একটা table:

পরিস্থিতিMediator ব্যবহার করবে?কেন
অনেক objects এলোমেলো জালে একে অপরকে call করছেহ্যাঁStar shape জাল সরিয়ে দেয়
Coordination rules অনেক class-এ ছড়িয়ে আছেহ্যাঁRules একটা পাঠযোগ্য class-এ জমা হয়
একটা component reuse করা যাচ্ছে না কারণ সে অনেক siblings চেনেহ্যাঁComponents স্বাধীন হয়ে যায়
শুধু cooperation পরিবর্তন করতে বারবার widgets subclass করছহ্যাঁSubclassing-এর বদলে mediator swap করো
মাত্র দুটো object, একটা সহজ দিকে কথা বলছেনাDirect call বেশি সহজ আর স্পষ্ট
শুধু অনেক listeners-কে news broadcast করতে চাওনাসেটা Observer pattern-এর কাজ
Interaction logic ছোট আর কখনো বাড়বে নানাবাড়তি hop worth it না

বাস্তব Software-এ কোথায় দেখা যায়

এই pattern শুধু স্কুলের খেলনা না। এটা বাস্তব দুনিয়া চালায়।

  • Chat server আর group chat। WhatsApp group-এ তুমি সব ৫০ জন member-কে আলাদা আলাদা message পাঠাও না। তুমি server-এ একটা message পাঠাও, আর server সবার কাছে deliver করে। Server হলো mediator। অনেক tutorial ঠিক এই কারণেই chat room-কে classic mediator উদাহরণ হিসেবে ব্যবহার করে।
  • .NET-এ MediatR। হাজার হাজার company ব্যবহার করে; controllers commands পাঠায়, mediator সেগুলো handlers-এ route করে, আর দুটো কখনো একে অপরকে import করে না।
  • Air traffic control system। বাস্তব ATC software literally একটা mediator: aircraft, radar feed আর ground vehicle সব একটা central system-এর মাধ্যমে coordinate করে, কখনো সরাসরি না। আমাদের গল্প কোনো রূপক না — এটা আসল architecture।
  • UI dialog box। GUI framework-এ, একটা dialog window প্রায়ই তার buttons, text box আর checkbox-এর জন্য mediator হিসেবে কাজ করে। "OK" button নিজেকে disable করে না; dialog সব field দেখে আর সিদ্ধান্ত নেয়।
  • Open-source উদাহরণ। iluwatar-এর java-design-patterns repository-তে একটা complete runnable mediator উদাহরণ আছে, আর Refactoring Guru দশটা ভাষায় দেখায়।

ছাত্রছাত্রীরা যে সাধারণ ভুল করে ⚠️

⚠️

ভুল ১: Mediator-কে God Object বানিয়ে ফেলা। এটাই সবচেয়ে বড় বিপদ। Mediator সব coordination logic জমা করে — সেটাই তার কাজ। কিন্তু ক্রমাগত feed করতে থাকলে এটা ২,০০০ লাইনের একটা দানব হয়ে যায় যেটা সব কিছু সম্পর্কে সব কিছু জানে। Components থেকে সরানো complexity অদৃশ্য হয়নি; concentrated হয়েছে। সমাধান: যখন একটা mediator অনেক unrelated কাজ handle করে, সেটাকে দুই বা তিনটা ছোট mediator-এ ভাগ করো — একটা প্রতি screen, একটা প্রতি zone। বাস্তব ঢাকা বিমানবন্দরে ground movement, takeoff আর approach-এর জন্য আলাদা controllers আছে। এমনকি তারিকও সব কিছু একা করেন না।

⚠️

ভুল ২: Components-কে গোপনে direct reference রাখতে দেওয়া। কিছু ছাত্রছাত্রী mediator যোগ করে কিন্তু "just in case" পুরনো direct call-ও রেখে দেয়। এখন তোমার কাছে জাল আর তারা দুটোই আছে — দুই দুনিয়ার সবচেয়ে খারাপ দিক, সাথে দুটো truth source যেগুলো conflict করতে পারে। একবার tower তৈরি হলে, সব plane-to-plane radio বন্ধ করতে হবে। পুরনো references delete করো। কঠোর থাকো, aviation rules যেমন কঠোর।

আরো দুটো ছোট:

  • Component-এর business logic mediator-এর ভেতরে রাখা। Tower ঠিক করে কে কখন নামে। সে বিমান উড়ায় না। প্রতিটা component-এর নিজের কাজ সেই component-এর ভেতরে রাখো; mediator শুধু coordinate করে।
  • Mediator interface অনেক বড় করা। একটা notify(sender, event) দিয়ে শুরু করো। Named methods শুধু তখনই যোগ করো যখন events সত্যিই একে অপরের থেকে ভিন্ন হয়।

কাজিনদের সাথে তুলনা

ছাত্রছাত্রীরা প্রায়ই Mediator, Observer আর Facade গুলিয়ে ফেলে। এখানে family ছবি:

প্রশ্নMediatorObserverFacade
আকৃতিStar: সবাই centre-এ আর centre থেকেএকটা subject অনেক listeners-এএকটা complex subsystem-এর সহজ দরজা
দিকTwo-way (components tower-কে notify করে, tower commands দেয়)One-way broadcastOne-way (clients ভেতরে call করে)
Logic কে ধরে?Mediator সব coordination rules ধারণ করেLogic প্রতিটা observer-এ থাকেLogic subsystem-এ থাকে
Parts কি centre চেনে?হ্যাঁ, প্রতিটা component mediator চেনেSubject শুধু listener interface চেনেSubsystem facade-এর অস্তিত্বই জানে না
বাস্তব জীবনের ছবিAir traffic control towerYouTube channel আর subscribersHotel reception desk

আরেকটা interesting তথ্য: একটা mediator প্রায়ই Observer ব্যবহার করে তৈরি হয়। Components mediator.notify() সরাসরি call করার বদলে, mediator সেই events-এ subscribe করতে পারে যেগুলো components publish করে। কোন pattern দেখছ সেটা ঠিক করার test: একটা central object কি coordination rules-এর মালিক? যদি হ্যাঁ, এটা মূলত একটা mediator, ভেতরে যে যন্ত্রপাতিই ব্যবহার হোক।

কলেজ কর্নার: distributed system-এ একই trade-off choreography versus orchestration হিসেবে দেখা যায়। Microservices যেগুলো events emit করে আর একে অপরের প্রতি react করে সেগুলো choreographed (observer-এর মতো, কোনো centre নেই)। একটা workflow engine-এর দ্বারা চালিত microservices orchestrated (mediator-এর মতো, central brain)। কোনোটাই সবসময় সঠিক না: orchestration তোমাকে একটা পাঠযোগ্য flow আর একটা bottleneck দেয়; choreography দেয় resilience আর একটা debugging nightmare। n(n-1)/2 বনাম n argument classroom code থেকে cloud architecture পর্যন্ত scale করে।

এক ছবিতে পুরো Pattern 🗺️

চিত্র ৯: একটা mind map-এ Mediator সম্পর্কে সব কিছু — পরীক্ষার আগে এটা থেকে revise করো।

দ্রুত Revision Box

+--------------------------------------------------------------+
|                  MEDIATOR — QUICK REVISION                   |
+--------------------------------------------------------------+
| What     : Objects stop calling each other; all talk goes    |
|            through ONE central mediator.                     |
| Picture  : Air traffic control tower + planes (a star).      |
| Parts    : Mediator interface, Concrete Mediator,            |
|            Components (know ONLY the mediator).              |
| Key call : mediator.notify(sender, event)                    |
| Maths    : edges drop from n(n-1)/2 to n.                    |
| Wins     : Loose coupling, rules in one place, reusable      |
|            components, easy to add new components.           |
| Danger   : Mediator can grow into a God Object — split it!   |
| Cousins  : Observer = one-way broadcast;                     |
|            Facade   = one-way simple door.                   |
| Used in  : Chat servers, MediatR (.NET), ATC software,       |
|            UI dialogs.                                       |
+--------------------------------------------------------------+

Practice Exercises ✏️

এগুলো নিজে try করো। উপরের TypeScript airport code থেকে শুরু করো।

  1. দুটো runway। DelhiTower-কে একটার বদলে দুটো runway দাও। Tower যে runway free সেখানে বিমান পাঠাবে, আর শুধু তখনই queue করবে যখন দুটোই ব্যস্ত। লক্ষ্য করো তুমি শুধু tower পরিবর্তন করলে — Flight-এ একটা line-ও না। Pattern-এর শক্তি অনুভব করো।

  2. কম জ্বালানির অগ্রাধিকার। ক্যাপ্টেন রাহেলার flight-এ জ্বালানি কম। "request-landing-urgent" event যোগ করো। Tower urgent বিমানগুলোকে waiting queue-এর সামনে রাখবে। আবার গণনা করো কতটা class edit করলে। উত্তর একটা হওয়া উচিত।

  3. ক্লাসরুম মনিটর। একটা Classroom mediator বানাও। Components: Student objects আর একটা Teacher object। একজন student কখনো সরাসরি teacher-এর সাথে কথা বলে না; student class monitor-কে বলে (mediator.notify(student, "doubt")), আর monitor ঠিক করে এখনই teacher-এর কাছে সন্দেহ forward করবে কিনা নাকি doubt-clearing period-এর জন্য queue করবে। পুরো কথোপকথন print করো।

  4. Smart form (চ্যালেঞ্জ)। তিনটা components সহ একটা SignupDialog mediator তৈরি করো: CountryDropdown, PinCodeField আর SubmitButton। Rules: country বদলালে PIN code পুনরায় check করতে হবে (বাংলাদেশের PIN code ৬ সংখ্যার); PIN code valid না হওয়া পর্যন্ত Submit button disabled থাকবে। সব rules dialog-এর ভেতরে থাকতে হবে। তারপর চতুর্থ component যোগ করো — একটা "অন্য ঠিকানায় পাঠাও" checkbox যেটা একটা দ্বিতীয় address field দেখায় — আর check করো কতটা existing class edit করতে হলো। উত্তর যদি "শুধু mediator" হয়, তুমি pattern আয়ত্ত করেছ।

  5. গণিত check (কলেজ)। ৩০টা components-এর সিস্টেমের জন্য n(n-1)/2 ব্যবহার করে সর্বোচ্চ direct connections গণনা করো, তারপর mediator-star count করো। একটা বাক্যে লেখো কেন পার্থক্যটা code লেখার চেয়ে testing-এর জন্য বেশি গুরুত্বপূর্ণ। (Hint: প্রতিটা connection একটা path যেটা test-কে cover করতে হবে।)

সচরাচর জিজ্ঞাসা

এক লাইনে Mediator pattern কী?
এটা একটা behavioral design pattern যেখানে objects একে অপরের সাথে সরাসরি কথা বলা বন্ধ করে দেয় — সব message একটা central object-এর মাধ্যমে যায়, যেটাকে mediator বলে।
Control tower কেন Mediator pattern-এর ভালো উদাহরণ?
পাইলটরা কখনো অন্য পাইলটের সাথে কথা বলে না ঠিক করতে যে কে আগে নামবে। প্রতিটা পাইলট শুধু tower-এর সাথে কথা বলে, আর tower সব সিদ্ধান্ত নেয়। Tower-টাই হলো mediator।
Mediator আর Observer কি একই জিনিস?
না। Observer হলো একটা subject অনেক listener-কে broadcast করছে। Mediator হলো একটা central brain যেটা অনেক component-এর মধ্যে two-way কথাবার্তা coordinate করে — এই components একে অপরকে কখনো চেনে না।
Mediator pattern-এর সবচেয়ে বড় বিপদ কী?
Mediator ধীরে ধীরে 'God Object' হয়ে যেতে পারে — একটা বিশাল class যেটা সব কিছু জানে আর সব কিছু করে। Mediator অনেক বড় হয়ে গেলে সেটাকে ছোট ছোট mediator-এ ভাগ করো।
বাস্তব software-এ Mediator কোথায় ব্যবহার হয়?
WhatsApp group chat-এর মতো chat server, .NET-এর MediatR library, air traffic control software আর user interface-এর dialog box — সব জায়গায় mediator-এর idea ব্যবহার হয়।

আরো দেখো

সম্পর্কিত পাঠ