Asosiy kontentga o‘tish
Innovialabs

Kompozitsiya yoki meros: qachon qaysi birini tanlash kerak

Chuqur4 daq

Qisqacha

Odatiy holatda kompozitsiyani tanlang: obyektlarni kichik, almashtiriladigan qismlardan yig‘ing. Merosni faqat haqiqiy va barqaror «bu — shu» munosabati hamda sayoz ierarxiya uchun qoldiring.

Qisqa javob

Kompozitsiya — obyekt boshqa obyektlarni o‘z ichiga oladi va ishni ularga topshiradi. Meros (inheritance) — klass boshqa klassning xususiy holati hisoblanadi va uning kodidan qayta foydalanadi.

«Merosdan ko‘ra kompozitsiyani afzal ko‘ring» qoidasi bejiz paydo bo‘lmagan: meros quyi klassni ota klassning ichki xatti-harakatiga bog‘lab qo‘yadi, kompozitsiya esa obyektlarni faqat kichik interfeyslar orqali bog‘laydi. Meros foydali vosita bo‘lib qoladi, lekin odatda qo‘llanilganidan torroq vazifalar uchun.

Mo‘rt bazaviy klass muammosi

Quyi klass ota klassning faqat public API’siga emas, ko‘pincha uni qanday amalga oshirganiga ham bog‘liq bo‘ladi. Ota klassni o‘zgartirasiz — merosxo‘rlar buziladi, garchi ularning kodiga hech kim tegmagan bo‘lsa ham.

class Collection:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

    def add_all(self, items):
        for item in items:
            self.add(item)


class CountingCollection(Collection):
    def __init__(self):
        super().__init__()
        self.count = 0

    def add(self, item):
        self.count += 1
        super().add(item)

    def add_all(self, items):
        self.count += len(items)
        super().add_all(items)

Ota klassdagi add_all qayta aniqlangan add ni chaqiradi, shuning uchun har bir element ikki marta sanaladi. Bundan ham yomoni: ota klass muallifi keyinchalik add_all ni to‘g‘ridan-to‘g‘ri qo‘shishga o‘zgartirsa, xato yo‘qoladi — yoki boshqa xato paydo bo‘ladi. Quyi klass o‘zi ko‘rmaydigan amalga oshirish detaliga bog‘langan.

Chuqur ierarxiyalar va kombinatsiyalar portlashi

Ikkinchi odatiy muammo — bir nechta mustaqil o‘lchamni tasvirlashga urinadigan ierarxiya:

  • Notification → EmailNotification, SmsNotification
  • keyin UrgentEmailNotification, UrgentSmsNotification
  • keyin ScheduledUrgentEmailNotification...

Har bir yangi o‘lcham (kanal, ustuvorlik, jadval) klasslar sonini ko‘paytiradi. Xatti-harakat besh darajaga yoyilgan, bitta metodni tushunish uchun butun super() chaqiruvlar zanjirini o‘qishga to‘g‘ri keladi.

Kompozitsiyaga refaktoring

Har bir o‘lchamni alohida komponentga ajrating va ularni birga yig‘ing:

interface Channel {
  send(to: string, text: string): Promise<void>;
}

interface Formatter {
  format(text: string): string;
}

class EmailChannel implements Channel {
  async send(to: string, text: string) { /* SMTP orqali yuborish */ }
}

class UrgentFormatter implements Formatter {
  format(text: string) { return `[URGENT] ${text}`; }
}

class Notifier {
  constructor(private channel: Channel, private formatter: Formatter) {}

  notify(to: string, text: string) {
    return this.channel.send(to, this.formatter.format(text));
  }
}

const notifier = new Notifier(new EmailChannel(), new UrgentFormatter());

Nimaga ega bo‘lasiz:

  • N × M o‘rniga N + M klass: yangi kanal ustuvorlikning yangi variantlarini talab qilmaydi.
  • Runtime’da almashtirish: kanalni konfiguratsiyadan tanlash mumkin.
  • Oson testlash: ota klassni mock qilish o‘rniga soxta Channel uzatasiz.
  • Aniq kontraktlar: Notifier faqat ikkita kichik interfeysga bog‘liq.

Oldingi bo‘limdagi sanovchi kolleksiya ham shunday tuzatiladi: undan meros olmang, balki kolleksiyani o‘rab, chaqiruvlarni unga topshiring. Shunda sizning add_all ichki kolleksiya o‘z metodlarini qanday amalga oshirganiga bog‘liq bo‘lmaydi.

Bosqichma-bosqich refaktoring rejasi

  1. Ierarxiyadagi o‘zgaruvchan o‘lchamlarni toping (kanal, saqlash, format, siyosat).
  2. Har bir o‘lcham uchun minimal metodli interfeys ajrating.
  3. Quyi klasslardagi xatti-harakatni shu interfeyslarning kichik implementatsiyalariga ko‘chiring.
  4. Qismlarni bitta klass konstruktori orqali uzating.
  5. Faqat qismlarni birlashtirgan bo‘sh quyi klasslarni o‘chiring.
  6. Xatti-harakat o‘zgarmasligi uchun oldin va keyin testlar bilan qoplang.

Meros qachon hali ham o‘rinli

VaziyatMeros mos keladimi?
O‘zgarmaydigan haqiqiy «bu — shu» munosabatiHa
Framework bazaviy klassni kengaytirishni talab qiladi (UI komponentlar, istisnolar, test-keyslar)Ha
Shablon metod: ota klass algoritmni belgilaydi, merosxo‘r bir-ikki qadamni to‘ldiradiKo‘pincha ha
Bir nechta yordamchi metoddan qayta foydalanishYo‘q — kompozitsiya yoki funksiyalar
Bir nechta mustaqil variatsiyaYo‘q — kompozitsiya
Ota klass uchinchi tomon kutubxonasidan va kengaytirishga mo‘ljallanmaganYo‘q — uni o‘rab oling

Amaliy qoidalar:

  • Ierarxiyalarni sayoz saqlang — odatda bir-ikki daraja yetarli.
  • Klassni meros uchun loyihalang yoki uni taqiqlang: kengaytirish uchun hujjatlashtirilmagan klasslarni final deb belgilang (Java; Kotlin’da klasslar sukut bo‘yicha yopiq; C#’da sealed).
  • Ota klass o‘z ichida chaqiradigan metodlarni qayta aniqlamang, agar bunga aniq ruxsat berilmagan bo‘lsa.
  • Liskov tekshiruvi: quyi klass ota klass ishlaydigan har qanday joyda ishlashi kerak. Agar u meros qilingan metodda «qo‘llab-quvvatlanmaydi» xatosini tashlasa — ierarxiya noto‘g‘ri qurilgan.

Keng tarqalgan xatolar

  • Turni ifodalash uchun emas, faqat kodni qayta ishlatish uchun meros olish.
  • Bir-biriga aloqasiz helper’lar to‘planadigan BaseService, BaseController, BaseManager klasslari.
  • Teskari chekka: oddiy quyi klass tushunarliroq bo‘ladigan joyda delegatsiya qatlamlari.
  • Merosxo‘rlar to‘g‘ridan-to‘g‘ri o‘zgartiradigan protected maydonlardagi ichki holat.

Ko‘p beriladigan savollar

Yo‘q. Bu kuchli bog‘liqlik vositasi bo‘lib, ko‘pincha noo‘rin qo‘llaniladi. Barqaror «bu — shu» munosabati, framework kengaytirish nuqtasi yoki shablon metod uchun meros sodda va o‘qilishi oson.

Bunda yordam beramiz

O‘zingiz shug‘ullanmasdan natija olishni istasangiz — biz har kuni shu bilan shug‘ullanamiz.

Loyihani muhokama qilish

Yana o‘qing

G‘oya yoki vazifangiz bormi? Bizga aytib bering

Ish kuni davomida javob beramiz va yechim taklif qilamiz. Konsultatsiya bepul.