বাংলা

জাভাস্ক্রিপ্ট ডেকোরেটর ব্যবহার করে মেটাডেটা পরিচালনা ও কোড পরিবর্তনের ক্ষমতা জানুন। আন্তর্জাতিক সেরা অনুশীলনের মাধ্যমে আপনার কোডকে আরও স্পষ্ট ও দক্ষ করে তুলুন।

জাভাস্ক্রিপ্ট ডেকোরেটরস: মেটাডেটা এবং কোড পরিবর্তনের উন্মোচন

জাভাস্ক্রিপ্ট ডেকোরেটর ক্লাস, মেথড, প্রপার্টি এবং প্যারামিটারের আচরণ পরিবর্তন এবং মেটাডেটা যোগ করার একটি শক্তিশালী ও সুন্দর উপায়। এটি লগিং, ভ্যালিডেশন, অথোরাইজেশন ইত্যাদির মতো ক্রস-কাটিং কনসার্ন (cross-cutting concerns) যোগ করার জন্য একটি ডিক্ল্যারেটিভ সিনট্যাক্স প্রদান করে। যদিও এটি এখনও একটি অপেক্ষাকৃত নতুন ফিচার, ডেকোরেটরগুলি জনপ্রিয়তা অর্জন করছে, বিশেষ করে টাইপস্ক্রিপ্টে, এবং এটি কোডের পঠনযোগ্যতা, রক্ষণাবেক্ষণযোগ্যতা এবং পুনঃব্যবহারযোগ্যতা উন্নত করার প্রতিশ্রুতি দেয়। এই নিবন্ধটি জাভাস্ক্রিপ্ট ডেকোরেটরের ক্ষমতা অন্বেষণ করবে, বিশ্বব্যাপী ডেভেলপারদের জন্য ব্যবহারিক উদাহরণ এবং অন্তর্দৃষ্টি প্রদান করবে।

জাভাস্ক্রিপ্ট ডেকোরেটর কী?

ডেকোরেটর মূলত এমন ফাংশন যা অন্য ফাংশন বা ক্লাসকে র‍্যাপ (wrap) করে। এগুলি ডেকোরেট করা উপাদানের মূল কোড সরাসরি পরিবর্তন না করেই তার আচরণ পরিবর্তন বা উন্নত করার একটি উপায় প্রদান করে। ডেকোরেটরগুলি ক্লাস, মেথড, অ্যাক্সেসর, প্রপার্টি বা প্যারামিটার ডেকোরেট করার জন্য @ চিহ্ন এবং তারপর একটি ফাংশনের নাম ব্যবহার করে।

এগুলিকে হায়ার-অর্ডার ফাংশনের জন্য সিনট্যাকটিক সুগার (syntactic sugar) হিসেবে বিবেচনা করুন, যা আপনার কোডে ক্রস-কাটিং কনসার্ন প্রয়োগ করার জন্য একটি পরিষ্কার এবং আরও পঠনযোগ্য উপায় প্রদান করে। ডেকোরেটর আপনাকে কার্যকরভাবে কনসার্ন পৃথক করতে সক্ষম করে, যা আরও মডুলার এবং রক্ষণাবেক্ষণযোগ্য অ্যাপ্লিকেশনের দিকে পরিচালিত করে।

ডেকোরেটরের প্রকারভেদ

জাভাস্ক্রিপ্ট ডেকোরেটর বিভিন্ন ধরণের হয়, যার প্রত্যেকটি আপনার কোডের বিভিন্ন উপাদানকে লক্ষ্য করে:

মৌলিক সিনট্যাক্স

একটি ডেকোরেটর প্রয়োগ করার সিনট্যাক্স খুবই সহজ:

@decoratorName
class MyClass {
  @methodDecorator
  myMethod( @parameterDecorator param: string ) {
    @propertyDecorator
    myProperty: number;
  }
}

এখানে এর একটি বিবরণ দেওয়া হলো:

ক্লাস ডেকোরেটর: ক্লাসের আচরণ পরিবর্তন

ক্লাস ডেকোরেটর হলো এমন ফাংশন যা ক্লাসের কনস্ট্রাক্টরকে আর্গুমেন্ট হিসেবে গ্রহণ করে। এগুলি ব্যবহার করা যেতে পারে:

উদাহরণ: ক্লাস তৈরির লগিং

ধরুন আপনি যখনই একটি ক্লাসের নতুন ইনস্ট্যান্স তৈরি হয়, তখন লগ করতে চান। একটি ক্লাস ডেকোরেটর এটি করতে পারে:

function logClassCreation(constructor: Function) {
  return class extends constructor {
    constructor(...args: any[]) {
      console.log(`Creating a new instance of ${constructor.name}`);
      super(...args);
    }
  };
}

@logClassCreation
class User {
  name: string;

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

const user = new User("Alice"); // Output: Creating a new instance of User

এই উদাহরণে, logClassCreation আসল User ক্লাসটিকে একটি নতুন ক্লাস দিয়ে প্রতিস্থাপন করে যা এটিকে এক্সটেন্ড করে। নতুন ক্লাসের কনস্ট্রাক্টর একটি বার্তা লগ করে এবং তারপর super ব্যবহার করে মূল কনস্ট্রাক্টরকে কল করে।

মেথড ডেকোরেটর: মেথডের কার্যকারিতা বৃদ্ধি

মেথড ডেকোরেটর তিনটি আর্গুমেন্ট গ্রহণ করে:

এগুলি ব্যবহার করা যেতে পারে:

উদাহরণ: মেথড কল লগিং

আসুন একটি মেথড ডেকোরেটর তৈরি করি যা প্রতিবার একটি মেথড কল করার সময় তার আর্গুমেন্টসহ লগ করে:

function logMethodCall(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Calling method ${propertyKey} with arguments: ${JSON.stringify(args)}`);
    const result = originalMethod.apply(this, args);
    console.log(`Method ${propertyKey} returned: ${result}`);
    return result;
  };

  return descriptor;
}

class Calculator {
  @logMethodCall
  add(x: number, y: number): number {
    return x + y;
  }
}

const calculator = new Calculator();
const sum = calculator.add(5, 3); // Output: Calling method add with arguments: [5,3]
                                 //         Method add returned: 8

logMethodCall ডেকোরেটর মূল মেথডটিকে র‍্যাপ করে। মূল মেথডটি কার্যকর করার আগে, এটি মেথডের নাম এবং আর্গুমেন্ট লগ করে। কার্যকর করার পরে, এটি রিটার্ন করা মানটি লগ করে।

অ্যাক্সেসর ডেকোরেটর: প্রপার্টি অ্যাক্সেস নিয়ন্ত্রণ

অ্যাক্সেসর ডেকোরেটর মেথড ডেকোরেটরের মতোই কিন্তু বিশেষভাবে গেটার এবং সেটার মেথড (অ্যাক্সেসর) এর উপর প্রয়োগ করা হয়। এগুলি মেথড ডেকোরেটরের মতো একই তিনটি আর্গুমেন্ট গ্রহণ করে:

এগুলি ব্যবহার করা যেতে পারে:

উদাহরণ: সেটার মান যাচাই করা

আসুন একটি অ্যাক্সেসর ডেকোরেটর তৈরি করি যা একটি প্রপার্টির জন্য সেট করা মান যাচাই করে:

function validateAge(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalSet = descriptor.set;

  descriptor.set = function (value: number) {
    if (value < 0) {
      throw new Error("Age cannot be negative");
    }
    originalSet.call(this, value);
  };

  return descriptor;
}

class Person {
  private _age: number;

  @validateAge
  set age(value: number) {
    this._age = value;
  }

  get age(): number {
    return this._age;
  }
}

const person = new Person();
person.age = 30; // Works fine

try {
  person.age = -5; // Throws an error: Age cannot be negative
} catch (error:any) {
  console.error(error.message);
}

validateAge ডেকোরেটর age প্রপার্টির সেটারকে ইন্টারসেপ্ট করে। এটি মানটি নেগেটিভ কিনা তা পরীক্ষা করে এবং যদি হয় তবে একটি এরর থ্রো করে। অন্যথায়, এটি মূল সেটারকে কল করে।

প্রপার্টি ডেকোরেটর: প্রপার্টি ডেসক্রিপ্টর পরিবর্তন

প্রপার্টি ডেকোরেটর দুটি আর্গুমেন্ট গ্রহণ করে:

এগুলি ব্যবহার করা যেতে পারে:

উদাহরণ: একটি প্রপার্টিকে রিড-অনলি করা

আসুন একটি প্রপার্টি ডেকোরেটর তৈরি করি যা একটি প্রপার্টিকে রিড-অনলি করে:

function readOnly(target: any, propertyKey: string) {
  Object.defineProperty(target, propertyKey, {
    writable: false,
  });
}

class Configuration {
  @readOnly
  apiUrl: string = "https://api.example.com";
}

const config = new Configuration();

try {
  (config as any).apiUrl = "https://newapi.example.com"; // Throws an error in strict mode
  console.log(config.apiUrl); // Output: https://api.example.com
} catch (error) {
  console.error("Cannot assign to read only property 'apiUrl' of object '#'", error);
}

readOnly ডেকোরেটর Object.defineProperty ব্যবহার করে প্রপার্টি ডেসক্রিপ্টর পরিবর্তন করে, writable কে false সেট করে। এখন প্রপার্টিটি পরিবর্তন করার চেষ্টা করলে একটি এরর হবে (স্ট্রিক্ট মোডে) অথবা এটি উপেক্ষা করা হবে।

প্যারামিটার ডেকোরেটর: প্যারামিটার সম্পর্কে মেটাডেটা প্রদান

প্যারামিটার ডেকোরেটর তিনটি আর্গুমেন্ট গ্রহণ করে:

প্যারামিটার ডেকোরেটর অন্যান্য প্রকারের তুলনায় কম ব্যবহৃত হয়, তবে এটি এমন পরিস্থিতিতে সহায়ক হতে পারে যেখানে আপনাকে নির্দিষ্ট প্যারামিটারের সাথে মেটাডেটা সংযুক্ত করতে হবে।

উদাহরণ: ডিপেন্ডেন্সি ইনজেকশন

প্যারামিটার ডেকোরেটর ডিপেন্ডেন্সি ইনজেকশন ফ্রেমওয়ার্কে সেইসব ডিপেন্ডেন্সি শনাক্ত করতে ব্যবহার করা যেতে পারে যা একটি মেথডে ইনজেক্ট করা উচিত। যদিও একটি সম্পূর্ণ ডিপেন্ডেন্সি ইনজেকশন সিস্টেম এই নিবন্ধের সুযোগের বাইরে, এখানে একটি সরলীকৃত চিত্র তুলে ধরা হলো:

const dependencies: any[] = [];

function inject(token: any) {
  return function (target: any, propertyKey: string | symbol, parameterIndex: number) {
    dependencies.push({
      target,
      propertyKey,
      parameterIndex,
      token,
    });
  };
}

class UserService {
  getUser(id: number) {
    return `User with ID ${id}`;
  }
}

class UserController {
  private userService: UserService;

  constructor(@inject(UserService) userService: UserService) {
    this.userService = userService;
  }

  getUser(id: number) {
    return this.userService.getUser(id);
  }
}

//Simplified retrieval of the dependencies
const userServiceInstance = new UserService();
const userController = new UserController(userServiceInstance);
console.log(userController.getUser(123)); // Output: User with ID 123

এই উদাহরণে, @inject ডেকোরেটর dependencies অ্যারেতে userService প্যারামিটার সম্পর্কে মেটাডেটা সংরক্ষণ করে। একটি ডিপেন্ডেন্সি ইনজেকশন কন্টেইনার তখন এই মেটাডেটা ব্যবহার করে সঠিক ডিপেন্ডেন্সি সমাধান এবং ইনজেক্ট করতে পারে।

বাস্তব প্রয়োগ এবং ব্যবহারের ক্ষেত্র

কোডের গুণমান এবং রক্ষণাবেক্ষণযোগ্যতা উন্নত করতে ডেকোরেটর বিভিন্ন পরিস্থিতিতে প্রয়োগ করা যেতে পারে:

ডেকোরেটর ব্যবহারের সুবিধা

ডেকোরেটর বেশ কিছু মূল সুবিধা প্রদান করে:

বিবেচ্য বিষয় এবং সেরা অনুশীলন

বিভিন্ন পরিবেশে ডেকোরেটর

যদিও ডেকোরেটরগুলি ESNext স্পেসিফিকেশনের অংশ, তবে বিভিন্ন জাভাস্ক্রিপ্ট পরিবেশে তাদের সমর্থন ভিন্ন হয়:

ডেকোরেটরের উপর বৈশ্বিক দৃষ্টিকোণ

বিভিন্ন অঞ্চল এবং ডেভেলপার কমিউনিটিতে ডেকোরেটরের গ্রহণ ভিন্ন হয়। কিছু অঞ্চলে, যেখানে টাইপস্ক্রিপ্ট ব্যাপকভাবে গৃহীত হয়েছে (যেমন, উত্তর আমেরিকা এবং ইউরোপের কিছু অংশ), ডেকোরেটর সাধারণত ব্যবহৃত হয়। অন্যান্য অঞ্চলে, যেখানে জাভাস্ক্রিপ্ট বেশি প্রচলিত বা যেখানে ডেভেলপাররা সহজ প্যাটার্ন পছন্দ করেন, সেখানে ডেকোরেটর কম প্রচলিত হতে পারে।

তদুপরি, সাংস্কৃতিক পছন্দ এবং শিল্পের মানগুলির উপর ভিত্তি করে নির্দিষ্ট ডেকোরেটর প্যাটার্নের ব্যবহার ভিন্ন হতে পারে। উদাহরণস্বরূপ, কিছু সংস্কৃতিতে, একটি আরও বিশদ এবং সুস্পষ্ট কোডিং শৈলী পছন্দ করা হয়, যেখানে অন্যগুলিতে, একটি আরও সংক্ষিপ্ত এবং প্রকাশযোগ্য শৈলী পছন্দ করা হয়।

আন্তর্জাতিক প্রকল্পগুলিতে কাজ করার সময়, এই সাংস্কৃতিক এবং আঞ্চলিক পার্থক্যগুলি বিবেচনা করা এবং এমন কোডিং মান স্থাপন করা অপরিহার্য যা সমস্ত দলের সদস্যদের কাছে স্পষ্ট, সংক্ষিপ্ত এবং সহজে বোধগম্য হয়। এর মধ্যে অতিরিক্ত ডকুমেন্টেশন, প্রশিক্ষণ বা মেন্টরিং প্রদান করা অন্তর্ভুক্ত থাকতে পারে যাতে সবাই ডেকোরেটর ব্যবহারে স্বাচ্ছন্দ্য বোধ করে।

উপসংহার

জাভাস্ক্রিপ্ট ডেকোরেটর কোডে মেটাডেটা যোগ এবং আচরণ পরিবর্তন করার জন্য একটি শক্তিশালী টুল। বিভিন্ন ধরণের ডেকোরেটর এবং তাদের ব্যবহারিক প্রয়োগগুলি বোঝার মাধ্যমে, ডেভেলপাররা আরও পরিষ্কার, রক্ষণাবেক্ষণযোগ্য এবং পুনঃব্যবহারযোগ্য কোড লিখতে পারে। যেহেতু ডেকোরেটরগুলি ব্যাপক গ্রহণযোগ্যতা পাচ্ছে, তারা জাভাস্ক্রিপ্ট ডেভেলপমেন্ট ল্যান্ডস্কেপের একটি অপরিহার্য অংশ হতে চলেছে। এই শক্তিশালী বৈশিষ্ট্যটি গ্রহণ করুন এবং আপনার কোডকে নতুন উচ্চতায় উন্নীত করার সম্ভাবনা উন্মোচন করুন। সর্বদা সেরা অনুশীলনগুলি অনুসরণ করতে এবং আপনার অ্যাপ্লিকেশনগুলিতে ডেকোরেটর ব্যবহারের পারফরম্যান্সের প্রভাব বিবেচনা করতে মনে রাখবেন। সতর্ক পরিকল্পনা এবং বাস্তবায়নের মাধ্যমে, ডেকোরেটরগুলি আপনার জাভাস্ক্রিপ্ট প্রকল্পগুলির গুণমান এবং রক্ষণাবেক্ষণযোগ্যতা উল্লেখযোগ্যভাবে উন্নত করতে পারে। হ্যাপি কোডিং!