برنامه نویسی

کاوش برنامه نویسی شی گرا با TypeScript

در دنیای توسعه نرم افزار، برنامه نویسی شی گرا (OOP) به یک پارادایم اساسی برای ایجاد برنامه های کاربردی پیچیده و مقیاس پذیر تبدیل شده است. یکی از محبوب ترین زبان های برنامه نویسی که از مفاهیم OOP پشتیبانی می کند TypeScript است. تایپ اسکریپت ابر مجموعه ای از جاوا اسکریپت است که تایپ استاتیک و سایر ویژگی ها را برای افزایش قابلیت نگهداری و خوانایی کد اضافه می کند. در این وبلاگ، قدرت برنامه نویسی شی گرا در TypeScript و اینکه چگونه می تواند به ما در ساخت برنامه های کاربردی قوی و کارآمد کمک کند را بررسی خواهیم کرد.

1. درک برنامه نویسی شی گرا (OOP):
برنامه نویسی شی گرا یک پارادایم برنامه نویسی است که بر ایجاد و دستکاری اشیا برای حل مسائل پیچیده تمرکز دارد. بر مفهوم طبقات و اشیاء، کپسولاسیون، وراثت و چندشکلی تأکید می کند. این اصول توسعه دهندگان را قادر می سازد کدهای ماژولار، قابل استفاده مجدد و قابل نگهداری بسازند.

2. کلاس ها و اشیا در TypeScript:
در TypeScript، یک کلاس طرحی برای ایجاد اشیا است. خصوصیات و رفتاری را که اشیاء کلاس خواهند داشت را تعریف می کند. ما می توانیم چندین نمونه از یک کلاس ایجاد کنیم که به عنوان اشیاء شناخته می شوند. اشیا حالت (خواص) و رفتار (روش) خود را دارند.

بیایید مثالی از کلاس “Person” در TypeScript بزنیم:

class Person {
  private name: string;
  private age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  public greet(): void {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

// Creating an instance of the Person class
const john = new Person("Kwame", 25);
john.greet(); // Output: Hello, my name is Kwame and I am 25 years old.
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در مثال بالا، کلاسی به نام “Person” با خصوصیات خصوصی (name و age)، یک سازنده برای مقداردهی اولیه آن ویژگی ها و یک روش عمومی greet() برای چاپ تبریک سپس یک نمونه از کلاس ایجاد می کنیم و آن را فراخوانی می کنیم greet() روش.

3. Encapsulation و Access Modifiers:
کپسوله‌سازی یک اصل OOP است که مجموعه داده‌ها و روش‌ها را در یک کلاس امکان‌پذیر می‌کند و جزئیات پیاده‌سازی داخلی را از دنیای بیرون پنهان می‌کند. در تایپ اسکریپت، می‌توانیم با استفاده از اصلاح‌کننده‌های دسترسی به کپسوله‌سازی برسیم.
سه تغییر دهنده دسترسی در TypeScript وجود دارد:

*public: اصلاح کننده پیش فرض. اعضای عمومی از هر کجا قابل دسترسی هستند.
*private: اعضای خصوصی فقط در کلاسی که آنها را تعریف می کند قابل دسترسی هستند.
*protected: اعضای محافظت شده در کلاسی که آنها و زیر کلاس هایشان را تعریف می کند قابل دسترسی هستند.

4. وراثت و چند شکلی:
وراثت به کلاس ها اجازه می دهد تا ویژگی ها و متدها را از کلاس های دیگر به ارث ببرند. استفاده مجدد از کد را ترویج می کند و به ما امکان می دهد کلاس های تخصصی تری را بر اساس کلاس های موجود ایجاد کنیم. TypeScript از وراثت واحد پشتیبانی می کند، جایی که یک کلاس می تواند از یک کلاس پایه واحد ارث بری کند.

class Animal {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  public makeSound(): void {
    console.log("Generic animal sound");
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }

  public makeSound(): void {
    console.log("Woof woof!");
  }
}

const myDog = new Dog("Buddy");
myDog.makeSound(); // Output: Woof woof!
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در مثال بالا، ما یک کلاس “Animal” با نام خاصیت محافظت شده و a داریم makeSound() روش. کلاس “Dog” کلاس “Animal” را گسترش می دهد و از آن خارج می شود makeSound() روشی برای ارائه صدای خاص برای سگ ها ما یک نمونه از کلاس “Dog” ایجاد می کنیم و آن را فراخوانی می کنیم makeSound() روش، که خروجی “Woof woof!”.

5. چند شکلی ما را قادر می سازد از یک رابط یا کلاس پایه برای نمایش چندین کلاس مرتبط استفاده کنیم. این به ما امکان می‌دهد کدهای انعطاف‌پذیرتر و قابل توسعه‌تری بنویسیم. TypeScript از چندشکلی از طریق وراثت و رابط ها پشتیبانی می کند.

interface Shape {
  calculateArea(): number;
}

class Rectangle implements Shape {
  private width: number;
  private height: number;

  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

  public calculateArea(): number {
    return this.width * this.height;
  }
}

class Circle implements Shape {
  private radius: number;

  constructor(radius: number) {
    this.radius = radius;
  }

  public calculateArea(): number {
    return Math.PI * Math.pow(this.radius, 2);
  }
}

const rectangle = new Rectangle(5, 10);
const circle = new Circle(3);

console.log(rectangle.calculateArea()); // Output: 50
console.log(circle.calculateArea());    // Output: 28.274333882308138
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مثال، ما یک رابط “Shape” را با a تعریف می کنیم calculateArea() روش. کلاس های “Rectangle” و “Circle” این رابط را پیاده سازی می کنند و پیاده سازی های خود را از روش ارائه می دهند. ما نمونه هایی از این کلاس ها را ایجاد می کنیم و the را فراخوانی می کنیم calculateArea() روشی که مساحت اشکال مربوطه را محاسبه و برمی گرداند.

6. انتزاع:
Abstraction یک مفهوم حیاتی در OOP است که به ما امکان می دهد موجودیت های پیچیده دنیای واقعی را به شیوه ای ساده و تعمیم یافته نشان دهیم. بر تعریف ویژگی ها و رفتارهای اساسی یک شی تمرکز دارد و در عین حال جزئیات غیر ضروری را پنهان می کند. در TypeScript، انتزاع را می توان از طریق کلاس ها و رابط های انتزاعی به دست آورد.

  • کلاس های انتزاعی: یک کلاس انتزاعی طرحی برای کلاس های دیگر است و نمی توان آن را مستقیماً نمونه سازی کرد. ممکن است شامل روش‌های انتزاعی (بدون اجرا) و روش‌های مشخص (با پیاده‌سازی) باشد. کلاس های فرعی که از یک کلاس انتزاعی به ارث می برند باید یک پیاده سازی برای متدهای انتزاعی ارائه دهند.
abstract class Animal {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  abstract makeSound(): void;

  public sleep(): void {
    console.log("Zzzz...");
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }

  public makeSound(): void {
    console.log("Woof woof!");
  }
}

const myDog = new Dog("Buddy");
myDog.makeSound(); // Output: Woof woof!
myDog.sleep();     // Output: Zzzz...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مثال کلاس Animal به صورت انتزاعی اعلام شده است و دارای متد انتزاعی است makeSound(). کلاس “Dog” کلاس “Animal” را گسترش می دهد و یک پیاده سازی برای آن ارائه می دهد makeSound() روش. ما یک نمونه از کلاس “Dog” ایجاد می کنیم و متدهای انتزاعی و ملموس را فراخوانی می کنیم.

7. رابط ها:
رابط قراردادی است که ساختار و رفتار یک شی را تعریف می کند. ویژگی ها و متدهایی را که یک کلاس باید پیاده سازی کند را توصیف می کند. اینترفیس ها ما را قادر می سازند تا به رفتارهای چندگانه وراثت مانند در TypeScript دست یابیم.

interface Shape {
  calculateArea(): number;
}

interface Color {
  color: string;
}

class Rectangle implements Shape, Color {
  private width: number;
  private height: number;
  public color: string;

  constructor(width: number, height: number, color: string) {
    this.width = width;
    this.height = height;
    this.color = color;
  }

  public calculateArea(): number {
    return this.width * this.height;
  }
}

const rectangle: Shape & Color = new Rectangle(5, 10, "blue");
console.log(rectangle.calculateArea()); // Output: 50
console.log(rectangle.color);          // Output: blue
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مثال دو رابط “Shape” و “Color” را تعریف می کنیم. کلاس “Rectangle” هر دو اینترفیس را پیاده سازی می کند و خواص و روش های مورد نیاز را ارائه می دهد. ما یک نمونه از کلاس “Rectangle” ایجاد می کنیم و به متدها و ویژگی های تعریف شده توسط اینترفیس ها دسترسی پیدا می کنیم.

8. ژنریک:
Generics به ما اجازه می دهد تا اجزای قابل استفاده مجدد ایجاد کنیم که می توانند با انواع داده ها کار کنند. آنها انعطاف پذیری و ایمنی نوع را با امکان تعریف انواعی که در زمان استفاده به جای اعلام تعیین می شوند، فراهم می کنند. ژنریک ها به طور گسترده در مجموعه ها، ساختارهای داده و الگوریتم ها استفاده می شوند.

class Box<T> {
  private value: T;

  constructor(value: T) {
    this.value = value;
  }

  public getValue(): T {
    return this.value;
  }
}

const numberBox = new Box<number>(10);
console.log(numberBox.getValue()); // Output: 10

const stringBox = new Box<string>("Hello");
console.log(stringBox.getValue()); // Output: Hello
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مثال، ما یک کلاس عمومی به نام “Box” ایجاد می کنیم که می تواند مقداری از هر نوع را در خود جای دهد. پارامتر type را تعریف می کنیم T هنگام ایجاد یک نمونه از کلاس را getValue() متد مقدار ذخیره شده از نوع مشخص شده را برمی گرداند.

9. لوازم جانبی (گیرنده و تنظیم کننده):
TypeScript از استفاده از Accessorها که به نام های دریافت کننده و تنظیم کننده نیز شناخته می شوند، برای دسترسی کنترل شده به ویژگی های کلاس پشتیبانی می کند. دریافت‌کننده‌ها و تنظیم‌کننده‌ها به ما این امکان را می‌دهند که هنگام بازیابی یا تخصیص مقادیر ویژگی، منطق سفارشی را تعریف کنیم، و امکان کپسوله‌سازی و اعتبارسنجی بهتر را فراهم می‌کند.

class Person {
  private _name: string;

  get name(): string {
    return this._name;
  }

  set name(newName: string) {
    if (newName.length > 0) {
      this._name = newName;
    } else {
      console.log("Name cannot be empty.");
    }
  }
}

const person = new Person();
person.name = "John";
console.log(person.name); // Output: John

person.name = ""; // Output: Name cannot be empty.
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مثال، ما یک کلاس “Person” را با یک ویژگی خصوصی _name تعریف می کنیم. ما یک گیرنده تعریف می کنیم name() و یک تنظیم کننده name(newName: string). تنظیم کننده نام جدید را تأیید می کند و مقدار را فقط در صورتی که خالی نباشد تعیین می کند. ویژگی name را با استفاده از گیرنده و تنظیم کننده اختصاص داده و بازیابی می کنیم.

نتیجه:

برنامه نویسی شی گرا یک پارادایم قدرتمند برای ساخت برنامه های پیچیده و قابل نگهداری است و TypeScript پشتیبانی قوی از مفاهیم OOP ارائه می دهد. از طریق کلاس‌ها، اشیاء، وراثت، کپسوله‌سازی، چندشکلی، انتزاع، ژنریک‌ها و ابزارهای دسترسی، TypeScript توسعه‌دهندگان را قادر می‌سازد تا کدهای ماژولار، قابل استفاده مجدد و نوع ایمن بنویسند. با پذیرش این اصول OOP، می توانید ساختار، قابلیت نگهداری و مقیاس پذیری پروژه های TypeScript خود را افزایش دهید.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

همچنین ببینید
بستن
دکمه بازگشت به بالا