সিঙ্গলটন প্যাটার্ন ব্যবহার করে আমরা নিশ্চিত করতে পারি যেন একটি ক্লাস থেকে একটিই মাত্র অবজেক্ট তৈরি করা হয় । সচরাচর আমরা একই ক্লাস থেকে প্রয়োজনমত ইনস্ট্যান্স তৈরি করে নেই । কিন্তু কখনো কখনো প্রয়োজন পড়ে সিস্টেমওয়াইড একই ইনস্ট্যান্স ব্যবহার করার কিংবা কখনো কখনো নতুন ইনস্ট্যান্স তৈরি করা বেশ রিসোর্স ইন্টেন্সিভ হয় । এরকম পরিস্থিতিতে আমরা সিঙ্গলটন প্যাটার্ন ব্যবহার করতে পারি । এর বাস্তব উদাহরণ হতে পারে ডাটাবেইজ কানেকশন । আমরা চাইবো আমাদের এ্যাপ্লিকেশন যেন একবারই ডাটাবেইজ এ কানেক্ট করে এবং পরে ঐ কানেকশনটিই বারবার ব্যবহার করে ।
পাইথনে সিঙ্গলটন প্যাটার্নটা বেশ কয়েকভাবে করা যায় । তবে সবচাইতে গ্রহনযোগ্য উপায় হচ্ছে ডেকোরেটর ব্যবহার করা । আমরা প্রথমেই কোড দেখে নেই –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#!/usr/bin/env python class singleton: def __init__(self, decorated): self._decorated = decorated def Instance(self): try: return self._instance except AttributeError: self._instance = self._decorated() return self._instance def __call__(self): raise TypeError('Singletons must be accessed through `Instance()`.') def __instancecheck__(self, inst): return isinstance(inst, self._decorated) @singleton class Person(object): def __str__(self): return 'Person object' try: p = Person() except TypeError, ex: print "ERROR: " + ex.message p1 = Person.Instance() p2 = Person.Instance() print "ID of p1 - " + str(id(p1)) print "ID of p2 - " + str(id(p2)) print "p1 is p2? " + str(p1 is p2) |
পাইথনে ডেকোরেটর আসলে callable অবজেক্ট যেটি অন্য একটি অবজেক্টকে আর্গুমেন্ট হিসেবে গ্রহন করে এবং এবং আরেকটি অবজেক্ট রিটার্ন করে । কোন ক্লাস বা ফাংশন এর উপর @ চিহ্ন সহ ডেকোরেটরের নাম লিখে আমরা ডেকোরেটর ব্যবহার করি । ডেকোরেটর কে আমরা সহজে এভাবে কল্পনা করতে পারি –
1 2 3 4 5 |
@decorator def callable(): do_something() callable() |
এর মানে দাড়াবে অনেকটা এরকম –
1 2 |
callable = decorator(callable) callable() |
তো এই জিনিসটিই আমরা সিঙ্গলটন প্যাটার্ন তৈরি করতে ব্যবহার করছি । প্রথমে আমরা একটি ক্লাস বেইজড ডেকোরেটর ডিফাইন করলাম এবং তারপর আমাদের Person ক্লাসে ডেকোরেটর এ্যাপ্লাই করলাম । আসলে কি ঘটছে এখানে? ব্যাপারটা আসলে অনেকটা এরকম –
1 |
p = Person() |
হয়ে যাচ্ছে –
1 2 |
Person = singleton(Person) # Person এখন singleton ক্লাসের একটি ইনস্ট্যান্স p = Person() # singleton ক্লাসকে আমরা কল করছি অর্থাৎ __call__ করা হচ্ছে ফলে এক্সেপশন থ্রো করছে |
আমরা আর চাইলেও Person ইনস্ট্যান্স তৈরি করতে পারবো না । তাই বাধ্য হয়ে আমরা Instance() কল করবো । আসলে আমাদের কলটি হবে অনেকটা এরকম –
1 2 |
Person = singleton(Person) # Person এখন singleton ক্লাসের একটি ইনস্ট্যান্স Person.Instance() # আমরা আসলে singleton ইন্সট্যান্সের Instance() মেথডই কল করছি |
singleton ক্লাস টি __init__ করার সময়ই আদি এবং অকৃত্রিম Person ক্লাসটি পাস করে দেওয়া হয় যেটি self._decorated এ থেকে যায় । এরপর Instance() মেথডের কাজ বেশ সহজ সরল । সে দেখে আগেই ইনস্ট্যান্স তৈরি করা আছে কিনা । না থাকলে self._decorated এ থাকা মূল ক্লাস থেকে একটি ইনস্ট্যান্স করে রিটার্ন করে এবং নিজের কাছে self._instance এ সেইভ করে ।
ক্লাস বেইজড ডেকোরেটর বুঝতে সমস্যা হলে এভাবে এক্সপেরিমেন্ট করে দেখা যায় –
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/usr/bin/env python class singleton: def __init__(self, decorated): pass class Person(object): pass print Person # ডেকোরেশনের আগে Person = singleton(Person) print Person # ডেকোরেশনের পরে |