আমি রেমন্ড হেট্টিনজারের পাইকন টক "সুপার বিবেচিত সুপার" দেখেছি এবং পাইথনের এমআরও (মেথড রেজোলিউশন অর্ডার) সম্পর্কে কিছুটা শিখেছি যা একটি ডিটারমিনিস্টিক উপায়ে "অভিভাবক" শ্রেণিগুলিকে লাইন করে তোলে। নির্ভরতা ইনজেকশন করতে আমরা নীচের কোডের মতো এটি আমাদের সুবিধার জন্য ব্যবহার করতে পারি। তাই এখন, স্বাভাবিকভাবেই, আমি super
সমস্ত কিছুর জন্য ব্যবহার করতে চাই !
নীচের উদাহরণে, User
বর্গ উভয় থেকে inheriting দ্বারা এটি এর নির্ভরতা ঘোষণা LoggingService
এবং UserService
। এটি বিশেষভাবে বিশেষ নয়। মজার অংশটি হ'ল আমরা ইউনিট টেস্টিংয়ের সময় মেথড রেজোলিউশন অর্ডারটি ম্যাক আউট নির্ভরতাগুলিও ব্যবহার করতে পারি। নীচের কোডটি এমন একটি তৈরি করে MockUserService
যা উত্তরাধিকার সূত্রে প্রাপ্ত UserService
এবং আমরা যে পদ্ধতিগুলি উপহাস করতে চাই তার একটি বাস্তবায়ন সরবরাহ করে। নীচের উদাহরণে, আমরা এর একটি বাস্তবায়ন সরবরাহ করি validate_credentials
। MockUserService
কোনও কল হ্যান্ডেল করার জন্য আমাদের এমআরওতে validate_credentials
আগে এটি অবস্থান করা উচিত UserService
। এই রাপার ক্লাস প্রায় তৈরি দ্বারা সম্পন্ন User
নামক MockUser
এবং এ থেকেই উত্তরাধিকারী থাকার User
এবং MockUserService
।
এখন, যখন আমরা MockUser.authenticate
এটি করি এবং এটি পরিবর্তিতভাবে, পদ্ধতি রেজোলিউশন অর্ডারে super().validate_credentials()
MockUserService
আগে কল করা হয় UserService
এবং যেহেতু এটি প্রস্তাব দেয় validate_credentials
এই বাস্তবায়নটির একটি কার্যকর প্রয়োগ ব্যবহার করা হবে। হ্যাঁ - আমরা UserService
আমাদের ইউনিট পরীক্ষায় সফলভাবে উপহাস করেছি । এটি UserService
কিছু ব্যয়বহুল নেটওয়ার্ক বা ডাটাবেস কল করতে পারে তা বিবেচনা করুন - আমরা সবেমাত্র এর ল্যাটেন্সি ফ্যাক্টরটি সরিয়েছি। UserService
লাইভ / প্রোড ডেটা স্পর্শ করার ঝুঁকিও নেই ।
class LoggingService(object):
"""
Just a contrived logging class for demonstration purposes
"""
def log_error(self, error):
pass
class UserService(object):
"""
Provide a method to authenticate the user by performing some expensive DB or network operation.
"""
def validate_credentials(self, username, password):
print('> UserService::validate_credentials')
return username == 'iainjames88' and password == 'secret'
class User(LoggingService, UserService):
"""
A User model class for demonstration purposes. In production, this code authenticates user credentials by calling
super().validate_credentials and having the MRO resolve which class should handle this call.
"""
def __init__(self, username, password):
self.username = username
self.password = password
def authenticate(self):
if super().validate_credentials(self.username, self.password):
return True
super().log_error('Incorrect username/password combination')
return False
class MockUserService(UserService):
"""
Provide an implementation for validate_credentials() method. Now, calls from super() stop here when part of MRO.
"""
def validate_credentials(self, username, password):
print('> MockUserService::validate_credentials')
return True
class MockUser(User, MockUserService):
"""
A wrapper class around User to change it's MRO so that MockUserService is injected before UserService.
"""
pass
if __name__ == '__main__':
# Normal useage of the User class which uses UserService to resolve super().validate_credentials() calls.
user = User('iainjames88', 'secret')
print(user.authenticate())
# Use the wrapper class MockUser which positions the MockUserService before UserService in the MRO. Since the class
# MockUserService provides an implementation for validate_credentials() calls to super().validate_credentials() from
# MockUser class will be resolved by MockUserService and not passed to the next in line.
mock_user = MockUser('iainjames88', 'secret')
print(mock_user.authenticate())
এটি বেশ চতুর মনে হলেও এটি কি পাইথনের একাধিক উত্তরাধিকার এবং পদ্ধতি সমাধানের আদেশের একটি ভাল এবং বৈধ ব্যবহার? আমি যখন যে আমি জাভা সঙ্গে গলি শিখেছি ভাবে উত্তরাধিকার সম্পর্কে চিন্তা সম্পূর্ণ ভুল, কারণ আমরা বলতে পারি না এই মতানুযায়ী User
একটি হল UserService
বা User
একটি হল LoggingService
। সেভাবে চিন্তা করে, উপরের কোডটি যেভাবে উত্তরাধিকার ব্যবহার করে তা ব্যবহার করে তা বোঝা যায় না। অথবা এটা? আমরা যদি কোডটি পুনরায় ব্যবহারের জন্য, এবং পিতামাতার-> সন্তানের সম্পর্কের ক্ষেত্রে চিন্তা না করে খালি উত্তরাধিকার ব্যবহার করি তবে এটিকে এত খারাপ বলে মনে হয় না।
আমি কি এটা ভুল করছি?