SOLID Principles TypeScript এ প্রয়োগ করা

TypeScript এর Best Practices এবং Design Patterns - টাইপস্ক্রিপ্ট (Typescript) - Web Development

234

SOLID হল পাঁচটি বেসিক প্রোগ্রামিং নীতি যা সফটওয়্যার ডিজাইন এবং কোড রিফ্যাক্টরিংকে সহজ ও মডুলার করে তোলে। এগুলি মূলত অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং (OOP) এর সাথে সম্পর্কিত, এবং টাইপস্ক্রিপ্টে এগুলি প্রয়োগ করা কোডের রিডেবিলিটি, রিইউসেবিলিটি এবং মেন্টেইনেবিলিটি উন্নত করতে সাহায্য করে।

SOLID Principles এর পূর্ণরূপ হল:

  • S - Single Responsibility Principle (SRP)
  • O - Open/Closed Principle (OCP)
  • L - Liskov Substitution Principle (LSP)
  • I - Interface Segregation Principle (ISP)
  • D - Dependency Inversion Principle (DIP)

এই নীতিগুলি TypeScript এ কীভাবে প্রয়োগ করা যায়, তা নিচে আলোচনা করা হল।


১. Single Responsibility Principle (SRP)

একটি ক্লাস বা মডিউল শুধুমাত্র একটি দায়িত্ব (responsibility) নেবে এবং সেই দায়িত্বের পরিবর্তন বা সম্পাদন করলে শুধুমাত্র সেই একটি কারণ থাকবে। এর মানে হল যে একটি ক্লাস, মেথড বা ফাংশন একটি নির্দিষ্ট কাজ করবে এবং অন্য কোন দায়িত্ব নেবে না।

উদাহরণ:

class Invoice {
  constructor(public amount: number, public date: Date) {}

  calculateTotal(): number {
    return this.amount + (this.amount * 0.1); // 10% tax
  }
}

class InvoicePrinter {
  print(invoice: Invoice): void {
    console.log(`Invoice Date: ${invoice.date}`);
    console.log(`Amount: invoice.amount`);console.log(`Total:{invoice.amount}`);
    console.log(`Total: {invoice.calculateTotal()}`);
  }
}

এখানে, Invoice ক্লাসের কাজ শুধুমাত্র ইনভয়েসের তথ্য সংরক্ষণ করা এবং টোটাল হিসাব করা। InvoicePrinter ক্লাসটি শুধুমাত্র ইনভয়েস প্রিন্ট করার কাজ করে। এতে একাধিক দায়িত্বের বিভাজন হয়েছে এবং SRP অনুসরণ করা হয়েছে।


২. Open/Closed Principle (OCP)

এই নীতির মতে, কোডটি এমনভাবে ডিজাইন করতে হবে যাতে এটি নতুন ফিচারের জন্য ওপেন এবং বিদ্যমান ফিচারের জন্য ক্লোজড থাকে। অর্থাৎ, যখন নতুন ফিচার যোগ করতে হয়, তখন পুরনো কোডে কোনো পরিবর্তন না করে নতুন কোড যোগ করতে হবে।

উদাহরণ:

abstract class Shape {
  abstract calculateArea(): number;
}

class Circle extends Shape {
  constructor(public radius: number) {
    super();
  }

  calculateArea(): number {
    return Math.PI * this.radius * this.radius;
  }
}

class Square extends Shape {
  constructor(public sideLength: number) {
    super();
  }

  calculateArea(): number {
    return this.sideLength * this.sideLength;
  }
}

class AreaCalculator {
  calculate(shape: Shape): number {
    return shape.calculateArea();
  }
}

এখানে, Shape ক্লাস একটি অ্যাবস্ট্রাক্ট ক্লাস, এবং Circle এবং Square ক্লাসগুলি তা এক্সটেন্ড করেছে। AreaCalculator নতুন নতুন শেপের জন্য কোডে কোনো পরিবর্তন না করে নতুন শেপের জন্য এলগরিদম যোগ করতে পারে।


৩. Liskov Substitution Principle (LSP)

Liskov Substitution Principle বলে যে, যদি একটি ক্লাস B ক্লাস A থেকে ইনহেরিট করে, তবে B ক্লাসের ইনস্ট্যান্স দিয়ে A ক্লাসের জায়গায় ব্যবহার করা উচিত এবং সেই ব্যবহারকৃত ক্লাসটি সঠিকভাবে কাজ করবে।

উদাহরণ:

class Bird {
  fly(): void {
    console.log("Flying...");
  }
}

class Sparrow extends Bird {
  fly(): void {
    console.log("Sparrow is flying...");
  }
}

class Ostrich extends Bird {
  fly(): void {
    throw new Error("Ostriches can't fly");
  }
}

এখানে, Ostrich ক্লাসটি Bird ক্লাসের বৈশিষ্ট্যগুলো সঠিকভাবে অনুসরণ করছে না, কারণ Ostrich ফ্লাই করতে পারে না। LSP অনুসারে, আমরা Bird ক্লাসের মধ্যে fly মেথডকে এমনভাবে ডিজাইন করব যাতে এটি সব ধরনের বর্ডের জন্য সমানভাবে কাজ করে।


৪. Interface Segregation Principle (ISP)

এই নীতির মতে, বড় ইন্টারফেসগুলিকে ছোট, নির্দিষ্ট ইন্টারফেসে বিভক্ত করা উচিত, যাতে ক্লাসগুলোকে তাদের প্রয়োজনীয় ইন্টারফেসগুলি ব্যবহার করতে হয়। একটি ক্লাসের উপর অপ্রয়োজনীয় ইন্টারফেস চাপানো উচিত নয়।

উদাহরণ:

interface Printer {
  print(): void;
}

interface Scanner {
  scan(): void;
}

class MultiFunctionPrinter implements Printer, Scanner {
  print(): void {
    console.log("Printing...");
  }

  scan(): void {
    console.log("Scanning...");
  }
}

class SimplePrinter implements Printer {
  print(): void {
    console.log("Printing...");
  }
}

এখানে, Printer এবং Scanner ইন্টারফেস দুটি আলাদা করা হয়েছে যাতে ক্লাসগুলো শুধুমাত্র প্রয়োজনীয় ফিচারগুলো গ্রহণ করতে পারে। MultiFunctionPrinter উভয় ফিচারই ধারণ করে, কিন্তু SimplePrinter শুধু প্রিন্ট ফিচার ধারণ করে, এর ফলে কোনো অপ্রয়োজনীয় ফিচার চাপানো হয়নি।


৫. Dependency Inversion Principle (DIP)

এই নীতি অনুযায়ী, উচ্চ স্তরের মডিউল (high-level modules) এবং নিম্ন স্তরের মডিউল (low-level modules) উভয়ই আবশ্যকভাবে ইন্টারফেসের মাধ্যমে সংযুক্ত হবে এবং নির্দিষ্ট কনক্রিট ক্লাসের উপর নির্ভর করা উচিত নয়।

উদাহরণ:

interface PaymentGateway {
  processPayment(amount: number): void;
}

class StripePayment implements PaymentGateway {
  processPayment(amount: number): void {
    console.log(`Processing payment of $${amount} through Stripe`);
  }
}

class PayPalPayment implements PaymentGateway {
  processPayment(amount: number): void {
    console.log(`Processing payment of $${amount} through PayPal`);
  }
}

class Checkout {
  constructor(private paymentGateway: PaymentGateway) {}

  checkout(amount: number): void {
    this.paymentGateway.processPayment(amount);
  }
}

const stripePayment = new StripePayment();
const checkoutWithStripe = new Checkout(stripePayment);
checkoutWithStripe.checkout(100);  // Output: "Processing payment of $100 through Stripe"

এখানে, Checkout ক্লাসটি সরাসরি StripePayment বা PayPalPayment ক্লাসের উপর নির্ভর করছে না, বরং PaymentGateway ইন্টারফেসের উপর নির্ভর করছে। এইভাবে, Checkout ক্লাসটি DIP অনুসরণ করছে এবং নতুন পেমেন্ট গেটওয়ে ইন্টিগ্রেশন সহজতর হবে।


সারাংশ

TypeScript এ SOLID Principles প্রয়োগ করলে আপনি আপনার কোডের কাঠামোকে আরও মডুলার, রিইউসেবল, এবং মেন্টেইনেবল করে তুলতে পারবেন। এগুলি আপনার প্রজেক্টের স্কেল বাড়ানোর জন্য খুবই কার্যকরী, কারণ এগুলোর মাধ্যমে কোডের জটিলতা কমানো, ভুল কমানো এবং ভবিষ্যতে উন্নয়ন বা রিফ্যাক্টরিংয়ের সুবিধা পাওয়া যায়।

Content added By
Promotion

Are you sure to start over?

Loading...