Murakkab TypeScript OOP namunalarini o'rganing. Ushbu qo'llanma klass dizayni prinsiplari, merosga qarshi kompozitsiya bahsi va global auditoriya uchun masshtablanadigan, saqlanadigan ilovalarni yaratish strategiyalarini o'z ichiga oladi.
TypeScript OOP Namunalari: Klass Dizayni va Meros Strategiyalari Qo'llanmasi
Zamonaviy dasturiy ta'minotni ishlab chiqish dunyosida TypeScript mustahkam, masshtablanadigan va saqlanadigan ilovalarni yaratish uchun asosiy vosita sifatida paydo bo'ldi. JavaScript ustiga qurilgan kuchli typing tizimi dasturchilarga xatolarni erta aniqlash va yanada bashorat qilinadigan kod yozish imkoniyatini beradi. TypeScript kuchining markazida Ob'ektga Yo'naltirilgan Dasturlash (OOP) prinsiplarini har tomonlama qo'llab-quvvatlashi yotadi. Biroq, shunchaki klassni qanday yaratishni bilish kifoya emas. TypeScript-ni mukammal o'zlashtirish klass dizayni, meros ierarxiyalari va turli arxitektura namunalari o'rtasidagi murosani chuqur tushunishni talab qiladi.
Ushbu qo'llanma o'zlarining o'rta mahoratini mustahkamlayotganlardan tortib tajribali arxitektorlargacha bo'lgan dasturchilarning global auditoriyasi uchun mo'ljallangan. Biz TypeScript-dagi OOPning asosiy tushunchalariga chuqur sho'ng'iymiz, klass dizaynining samarali strategiyalarini o'rganamiz va asrlar davomida davom etayotgan bahsni hal qilamiz: merosga qarshi kompozitsiya. Oxir-oqibat, siz tozalovchi, moslashuvchan va kelajakka yo'naltirilgan kod bazalariga olib keladigan asosli dizayn qarorlarini qabul qilish uchun bilim bilan ta'minlanasiz.
TypeScript-dagi OOP ustunlarini tushunish
Murakkab namunalarga sho'ng'ishdan oldin, TypeScript-ga tegishli bo'lgan Ob'ektga Yo'naltirilgan Dasturlashning to'rtta fundamental ustunini qayta ko'rib chiqish orqali mustahkam poydevor yarataylik.
1. Inkapsulyatsiya
Inkapsulyatsiya - bu ob'ekt ma'lumotlarini (xususiyatlarini) va shu ma'lumotlar ustida ishlaydigan usullarni bitta birlikka - klassga birlashtirish prinsipidir. Bundan tashqari, u ob'ektning ichki holatiga bevosita kirishni cheklashni o'z ichiga oladi. TypeScript bunga asosan kirish modifikatorlari orqali erishadi: public, private va protected.
Misol: Bank hisobvarag'i, unda balans faqat depozit va yechib olish usullari orqali o'zgartirilishi mumkin.
class BankAccount {
private balance: number = 0;
constructor(initialBalance: number) {
if (initialBalance >= 0) {
this.balance = initialBalance;
}
}
public deposit(amount: number): void {
if (amount > 0) {
this.balance += amount;
console.log(`Depozit qilindi: ${amount}. Yangi balans: ${this.balance}`);
}
}
public getBalance(): number {
// Biz balansni bevosita emas, balki usul orqali ochamiz
return this.balance;
}
}
2. Abstraksiya
Abstraksiya murakkab amalga oshirish tafsilotlarini yashirish va faqat ob'ektning muhim xususiyatlarini ochib berishni anglatadi. Bu bizga ostidagi murakkab mexanizmni tushunishga hojat qoldirmasdan yuqori darajadagi tushunchalar bilan ishlashga imkon beradi. TypeScript-da abstraksiya ko'pincha abstract klasslar va interfaces yordamida amalga oshiriladi.
Misol: Masofadan boshqarish pultidan foydalanganda siz shunchaki "Power" tugmasini bosasiz. Siz infraqizil signallar yoki ichki sxemalar haqida bilishingiz shart emas. Masofadan boshqarish pulti televizor funksiyasiga abstrakt interfeysni taqdim etadi.
3. Meros
Meros - bu yangi klass (kichik klass yoki hosil qilingan klass) mavjud klassdan (superklass yoki asosiy klass) xususiyatlar va usullarni meros qilib oladigan mexanizmdir. U kodni qayta ishlatishga yordam beradi va klasslar o'rtasida aniq "is-a" munosabatini o'rnatadi. TypeScript meros uchun extends kalit so'zidan foydalanadi.
Misol: `Manager` `Employee` turidir. Ular `name` va `id` kabi umumiy xususiyatlarga ega, lekin `Manager`da `subordinates` kabi qo'shimcha xususiyatlar bo'lishi mumkin.
class Employee {
constructor(public name: string, public id: number) {}
getProfile(): string {
return `Ism: ${this.name}, ID: ${this.id}`;
}
}
class Manager extends Employee {
constructor(name: string, id: number, public subordinates: Employee[]) {
super(name, id); // Ota konstruktoriga qo'ng'iroq qiling
}
// Menejerlar ham o'z usullariga ega bo'lishlari mumkin
delegateTask(): void {
console.log(`${this.name} vazifalarni topshirmoqda.`);
}
}
4. Polimorfizm
"Ko'p shakllar" degan ma'noni anglatuvchi polimorfizm turli klasslarning ob'ektlariga umumiy superklass ob'ektlari sifatida qarash imkonini beradi. U bitta interfeysga (usul nomi kabi) turli xil asosiy shakllarni (amalga oshirishlarni) ifodalash imkoniyatini beradi. Bunga ko'pincha usulni bekor qilish orqali erishiladi.
Misol: `Circle` ob'ekti uchun `render()` usuli `Square` ob'ektiga nisbatan boshqacha harakat qiladi, garchi ikkalasi ham `Shape` bo'lsa ham.
abstract class Shape {
abstract draw(): void; // Abstrakt usul kichik klasslar tomonidan amalga oshirilishi kerak
}
class Circle extends Shape {
draw(): void {
console.log("Doira chizish.");
}
}
class Square extends Shape {
draw(): void {
console.log("Kvadrat chizish.");
}
}
function renderShapes(shapes: Shape[]): void {
shapes.forEach(shape => shape.draw()); // Polimorfizm harakatda!
}
const myShapes: Shape[] = [new Circle(), new Square()];
renderShapes(myShapes);
// Natija:
// Doira chizish.
// Kvadrat chizish.
Buyuk bahs: Merosga qarshi kompozitsiya
Bu OOPdagi eng muhim dizayn qarorlaridan biridir. Zamonaviy dasturiy ta'minotda keng tarqalgan fikr "merosdan ko'ra kompozitsiyaga ustunlik berish"dir. Keling, nima uchun ekanligini chuqur o'rganib chiqamiz.
Meros nima? "is-a" munosabati
Meros asosiy klass va hosil qilingan klass o'rtasida qattiq bog'lanish yaratadi. Qachonki siz `extends`dan foydalansangiz, siz yangi klass asosiy klassning ixtisoslashgan versiyasi ekanligini aytasiz. Bu aniq ierarxik munosabat mavjud bo'lganda kodni qayta ishlatish uchun kuchli vositadir.
- Afzalliklari:
- Kodni qayta ishlatish: Umumiy mantiq asosiy klassda bir marta aniqlanadi.
- Polimorfizm: Bizning `Shape` misolimizda ko'rinib turganidek, nafis, polimorfik xatti-harakatga imkon beradi.
- Aniq ierarxiya: U real, yuqoridan pastga tasniflash tizimini modellashtiradi.
- Kamchiliklari:
- Qattiq bog'lanish: Asosiy klassdagi o'zgarishlar beixtiyor hosil qilingan klasslarni buzishi mumkin. Bu "mo'rt asosiy klass muammosi" sifatida tanilgan.
- Ierarxiya do'zaxi: Haddan tashqari foydalanish tushunish va saqlash qiyin bo'lgan chuqur, murakkab va qat'iy meros zanjirlariga olib kelishi mumkin.
- Moslashuvchan emas: Klass TypeScript-da faqat bitta klassdan meros bo'lishi mumkin (bitta meros), bu cheklaydigan bo'lishi mumkin. Siz bir nechta, aloqasi bo'lmagan klasslardan xususiyatlarni meros qilib ololmaysiz.
Meros qachon yaxshi tanlov bo'ladi?
Munosabat chinakam "is-a" bo'lganda va barqaror bo'lsa va o'zgarishi dargumon bo'lganda, merosdan foydalaning. Misol uchun, `CheckingAccount` va `SavingsAccount` ikkalasi ham asosan `BankAccount` turlaridir. Ushbu ierarxiya mantiqan to'g'ri keladi va qayta modellashtirilishi dargumon.
Kompozitsiya nima? "has-a" munosabati
Kompozitsiya murakkab ob'ektlarni kichikroq, mustaqil ob'ektlardan qurishni o'z ichiga oladi. Klass boshqa narsa bo'lish o'rniga, unda kerakli funksionallikni ta'minlaydigan boshqa ob'ektlar bor. Bu bo'sh bog'lanishni yaratadi, chunki klass faqat tarkibiy ob'ektlarning ochiq interfeysi bilan o'zaro ta'sir qiladi.
- Afzalliklari:
- Moslashuvchanlik: Funktsionallikni tarkibiy ob'ektlarni almashtirish orqali ish vaqtida o'zgartirish mumkin.
- Bo'sh bog'lanish: Tarkibli klass o'zi ishlatadigan komponentlarning ichki ishlarini bilishi shart emas. Bu kodni sinovdan o'tkazish va saqlashni osonlashtiradi.
- Ierarxiya muammolaridan qochish: Chigallashgan meros daraxtini yaratmasdan, turli manbalardan funksiyalarni birlashtirishingiz mumkin.
- Aniq javobgarliklar: Har bir komponent klassi bitta javobgarlik prinsipiga rioya qilishi mumkin.
- Kamchiliklari:
- Ko'proq Boilerplate: Oddiy meros modeliga nisbatan turli komponentlarni ulash ko'proq kodni talab qilishi mumkin.
- Ierarxiyalar uchun kamroq intuitiv: U meros kabi tabiiy taksonomiyalarni to'g'ridan-to'g'ri modellashtirmaydi.
Amaliy misol: Mashina
`Car` - kompozitsiyaning mukammal namunasidir. `Car` `Engine` turi emas, shuningdek, u `Wheel` turi ham emas. Buning o'rniga, `Car`da `Engine` bor va `Wheels` bor.
// Komponent klasslari
class Engine {
start() {
console.log("Dvigatel ishga tushmoqda...");
}
}
class GPS {
navigate(destination: string) {
console.log(`Manzilga yo'naltirish ${destination}...`);
}
}
// Kompozit klass
class Car {
private readonly engine: Engine;
private readonly gps: GPS;
constructor() {
// Mashina o'z qismlarini yaratadi
this.engine = new Engine();
this.gps = new GPS();
}
driveTo(destination: string) {
this.engine.start();
this.gps.navigate(destination);
console.log("Mashina yo'lda.");
}
}
const myCar = new Car();
myCar.driveTo("Nyu-York Siti");
Ushbu dizayn juda moslashuvchan. Agar biz `ElectricEngine` bilan `Car` yaratmoqchi bo'lsak, bizga yangi meros zanjiri kerak emas. Biz `Car`ga o'z komponentlarini taqdim etish uchun Dependency Injection-dan foydalanishimiz mumkin, bu uni yanada modulli qiladi.
interface IEngine {
start(): void;
}
class PetrolEngine implements IEngine {
start() { console.log("Benzin dvigateli ishga tushmoqda..."); }
}
class ElectricEngine implements IEngine {
start() { console.log("Jim elektr dvigateli ishga tushmoqda..."); }
}
class AdvancedCar {
// Mashina aniq klassga emas, balki abstraksiyaga (interfeysga) bog'liq
constructor(private engine: IEngine) {}
startJourney() {
this.engine.start();
console.log("Sayohat boshlandi.");
}
}
const tesla = new AdvancedCar(new ElectricEngine());
tesla.startJourney();
const ford = new AdvancedCar(new PetrolEngine());
ford.startJourney();
TypeScript-dagi ilg'or strategiyalar va namunalari
Meros va kompozitsiya o'rtasidagi asosiy tanlovdan tashqari, TypeScript murakkab va moslashuvchan klass dizaynlarini yaratish uchun kuchli vositalarni taqdim etadi.1. Abstrakt klasslar: Meros uchun reja
Qachonki sizda kuchli "is-a" munosabat mavjud bo'lsa, lekin asosiy klasslarning o'z-o'zidan yaratilishiga yo'l qo'ymaslikni istasangiz, `abstract` klasslardan foydalaning. Ular umumiy usullar va xususiyatlarni belgilaydigan reja sifatida ishlaydi va hosil qilingan klasslar amalga oshirishi kerak bo'lgan `abstract` usullarini e'lon qilishi mumkin.
Foydalanish holati: To'lovlarni qayta ishlash tizimi. Siz har bir shlyuzda `pay()` va `refund()` usullari bo'lishi kerakligini bilasiz, lekin amalga oshirish har bir provayderga (masalan, Stripe, PayPal) xosdir.
abstract class PaymentGateway {
constructor(public apiKey: string) {}
// Barcha kichik klasslar tomonidan baham ko'riladigan aniq usul
protected connect(): void {
console.log("To'lov xizmatiga ulanish...");
}
// Kichik klasslar amalga oshirishi kerak bo'lgan abstrakt usullar
abstract processPayment(amount: number): boolean;
abstract issueRefund(transactionId: string): boolean;
}
class StripeGateway extends PaymentGateway {
processPayment(amount: number): boolean {
this.connect();
console.log(`${amount} Stripe orqali qayta ishlanmoqda.`);
return true;
}
issueRefund(transactionId: string): boolean {
console.log(`${transactionId} tranzaksiyasi Stripe orqali qaytarilmoqda.`);
return true;
}
}
// const gateway = new PaymentGateway("key"); // Xato: Abstrakt klassning nusxasini yaratib bo'lmaydi.
const stripe = new StripeGateway("sk_test_123");
stripe.processPayment(100);
2. Interfeyslar: Xatti-harakatlar uchun shartnomalarni belgilash
TypeScript-dagi interfeyslar klass shakli uchun shartnoma belgilash usulidir. Ular klass qanday xususiyatlar va usullarga ega bo'lishi kerakligini belgilaydi, lekin ular hech qanday amalga oshirishni ta'minlamaydi. Klass bir nechta interfeysni `implement` qilishi mumkin, bu ularni kompozitsion va ajratilgan dizaynning asosiga aylantiradi.
Interfeys va Abstrakt Klass
- Bir nechta yaqin aloqador klasslar o'rtasida amalga oshirilgan kodni baham ko'rmoqchi bo'lsangiz, abstrakt klassdan foydalaning.
- Turli xil, aloqasi bo'lmagan klasslar tomonidan amalga oshirilishi mumkin bo'lgan xatti-harakat uchun shartnoma belgilashni istasangiz, interfeysdan foydalaning.
Foydalanish holati: Tizimda ko'plab turli xil ob'ektlarni satr formatiga seriyalashtirish kerak bo'lishi mumkin (masalan, jurnallash yoki saqlash uchun). Ushbu ob'ektlar (`User`, `Product`, `Order`) aloqasi yo'q, lekin umumiy qobiliyatga ega.
interface ISerializable {
serialize(): string;
}
class User implements ISerializable {
constructor(public id: number, public name: string) {}
serialize(): string {
return JSON.stringify({ id: this.id, name: this.name });
}
}
class Product implements ISerializable {
constructor(public sku: string, public price: number) {}
serialize(): string {
return JSON.stringify({ sku: this.sku, price: this.price });
}
}
function logItems(items: ISerializable[]): void {
items.forEach(item => {
console.log("Seriyalashtirilgan element:", item.serialize());
});
}
const user = new User(1, "Alice");
const product = new Product("TSHIRT-RED", 19.99);
logItems([user, product]);
3. Miksinlar: Kodni qayta ishlatishga kompozitsion yondashuv
TypeScript faqat bitta merosga ruxsat berganligi sababli, agar siz bir nechta manbalardan kodni qayta ishlatmoqchi bo'lsangiz nima bo'ladi? Bu erda miksin namunasi paydo bo'ladi. Miksinlar - bu konstruktorni qabul qiladigan va uni yangi funksionallik bilan kengaytiradigan yangi konstruktorni qaytaradigan funktsiyalardir. Bu kompozitsiya shakli bo'lib, u sizga klassga qobiliyatlarni "aralashtirish" imkonini beradi.
Foydalanish holati: Siz ko'plab model klasslariga `Timestamp` (`createdAt`, `updatedAt` bilan) va `SoftDeletable` (`deletedAt` xususiyati va `softDelete()` usuli bilan) xatti-harakatlarini qo'shmoqchisiz.
// Miksinlar uchun Type yordamchisi
type Constructor = new (...args: any[]) => T;
// Timestamp Mixin
function Timestamped(Base: TBase) {
return class extends Base {
createdAt: Date = new Date();
updatedAt: Date = new Date();
};
}
// SoftDeletable Mixin
function SoftDeletable(Base: TBase) {
return class extends Base {
deletedAt: Date | null = null;
softDelete() {
this.deletedAt = new Date();
console.log("Element yumshoq tarzda o'chirildi.");
}
};
}
// Asosiy klass
class DocumentModel {
constructor(public title: string) {}
}
// Miksinlarni tuzish orqali yangi klass yarating
const UserAccountModel = SoftDeletable(Timestamped(DocumentModel));
const userAccount = new UserAccountModel("Mening foydalanuvchi hisobim");
console.log(userAccount.title);
console.log(userAccount.createdAt);
userAccount.softDelete();
console.log(userAccount.deletedAt);
Xulosa: Kelajakka yo'naltirilgan TypeScript ilovalarini yaratish
TypeScript-da Ob'ektga Yo'naltirilgan Dasturlashni o'zlashtirish sintaksisni tushunishdan dizayn falsafasini qabul qilishgacha bo'lgan sayohatdir. Klass tuzilishi, meros va kompozitsiyaga oid qarorlaringiz ilovangizning uzoq muddatli salomatligiga katta ta'sir ko'rsatadi.
Bu erda global rivojlanish amaliyotingiz uchun asosiy xulosalar keltirilgan:
- Ustunlardan boshlang: Inkapsulyatsiya, Abstraksiya, Meros va Polimorfizmni yaxshi tushunishingizga ishonch hosil qiling. Ular OOP lug'atidir.
- Merosdan ko'ra kompozitsiyaga ustunlik bering: Ushbu printsip sizni yanada moslashuvchan, modulli va sinovdan o'tadigan kodga olib keladi. Kompozitsiyadan boshlang va faqat aniq, barqaror "is-a" munosabat mavjud bo'lganda merosga murojaat qiling.
- Ish uchun to'g'ri vositadan foydalaning:
- Barqaror ierarxiyada haqiqiy ixtisoslashuv va kodni almashish uchun merosdan foydalaning.
- Ba'zi amalga oshirishni baham ko'rgan holda, shartnomani kuchga soladigan klasslar oilasi uchun umumiy asosni belgilash uchun Abstrakt klasslardan foydalaning.
- Har qanday klass tomonidan amalga oshirilishi mumkin bo'lgan xatti-harakatlar uchun shartnomalarni belgilash uchun Interfeyslardan foydalaning, bu esa haddan tashqari ajratishni rag'batlantiradi.
- Bitta merosning cheklovlarini bartaraf etib, bir nechta manbalardan klassga funksiyalarni tuzishingiz kerak bo'lganda Miksinlardan foydalaning.
Ushbu namunalarni tanqidiy o'ylab, ularning murosalarini tushunib, siz nafaqat bugungi kunda kuchli va samarali bo'lgan, balki siz yoki jamoangiz dunyoning qayerida bo'lishingizdan qat'i nazar, kelgusi yillarda moslashish, kengaytirish va saqlash oson bo'lgan TypeScript ilovalarini loyihalashtirishingiz mumkin.