نمط تصميم المحول في Python

المُقدّمة

نمط تصميم المحول هو شعبية نمط التصميم الإنشائي المستخدمة في هندسة البرمجيات. يبحث هذا الدليل في كيفية تنفيذ نمط تصميم المحول في Python.

أنماط التصميم هي حلول تشبه القوالب - وصفات عملية لحل المشكلات الشائعة المتكررة في تطوير البرامج. يعتمد نمط المحول على مفهوم المحول الواقعي! على سبيل المثال ، قد يحتوي شاحن الكمبيوتر المحمول على قابس ذي 3 سنون في النهاية ، لكن مقبس الحائط قد يكون فقط مقبسًا ثنائي السنون. لتوصيل شاحن 2 سنون في هذا المقبس ، سنحتاج إلى محول ، يقبل قابس 3 سنون ، و يتكيف الواجهة في 2 دبوس مأخذ.

شاحن 2 دبوس وشاحن 3 دبوس نفس الوظيفة الأساسية (توصيل الكهرباء من المقبس إلى الكمبيوتر المحمول) ، ولكن لديك بشكل مختلف، ويمكن للمرء بسهولة تكيف في الآخر. عندما يكون لديك مكونات برنامج لها نفس الوظيفة الأساسية ولكن بأشكال مختلفة ، يمكنك تطبيق نمط تصميم المحول.

يتبع نمط المحول هذا المبدأ الدقيق. يسمح لواجهتين غير متوافقين بالعمل معًا دون تعديل الأجزاء الداخلية لكل مكون. يتم تحقيق ذلك من خلال تكييف واجهة ، مع أخرى ، خارجيًا.

لنلقِ نظرة على بعض المصطلحات الأساسية قبل التعمق في عالم أنماط المحولات:

  • واجهة العميل: واجهة تحدد الوظائف التي يجب على العميل تنفيذها.
  • العميل: فئة تنفذ واجهة العميل.
  • المحول / الخدمة: الفئة غير المتوافقة التي تحتاج إلى التعاون مع واجهة العميل.
  • محول: الفئة التي تجعل التعاون بين الخدمة والعميل ممكنًا.

أنواع مختلفة من أنماط المحول

يمكن تنفيذ نمط تصميم المحول بطريقتين مختلفتين:

محول الكائن

باستخدام هذه الطريقة ، تطبق فئة المحول الأساليب من واجهة العميل. وبالتالي ، فإن كائن العميل وكائن المحول متوافقان مع بعضهما البعض. يشكل كائن الخدمة أ has-a العلاقة مع كائن المحول ، أي أن كائن الخدمة ينتمي إلى كائن المحول.

نحن نعلم أن فئة الخدمة غير متوافقة مع العميل. تلتف فئة المحول حول كائن الخدمة عن طريق إنشاء مثيل لها مع هذا الكائن. الآن ، يمكن الوصول إلى كائن الخدمة من خلال كائن المحول ، مما يسمح للعميل بالتفاعل معه.

يمكننا تنفيذ مهايئ الكائن في جميع لغات البرمجة الحديثة.

محول الفئة

بهذه الطريقة ، يكون للمحول ملف is-a العلاقة مع فئة الخدمة. في هذا السيناريو ، يقوم المحول بتنفيذ الطرق المطلوبة من قبل العميل ، لكنه يرث من عدة أدوات تكييف ، مما يمنحه القدرة على استدعاء وظائفهم غير المتوافقة مباشرة. أكبر عيب في هذا الاختلاف هو أنه لا يمكننا استخدامه إلا في لغات البرمجة التي تدعم الوراثة المتعددة للفئات.

تنفيذ نمط تصميم المحول في بايثون

في القسم أدناه ، سنقوم بتنفيذ نمط تصميم المحول في Python ، وتحديدًا باستخدام امتداد اختلاف محول الكائن. ينقسم هذا القسم إلى قسمين. أولاً ، سننشئ البيئة التي يجب استخدام نمط المحول فيها. من المهم أن ترى بوضوح كيف يمكن لهذا النمط أن يحل بعض مشكلات البرامج. سيستخدم القسم الثاني محولًا لحل المشكلة.

مشكلة عدم التوافق بين الفئات

لنلقِ نظرة على مشكلة التوافق عندما يقوم العميل وفئة الخدمة بتنفيذ وظائف مختلفة. قم بإنشاء فئة عميل بالطرق التالية واحفظها في مجلد باسم car.py:

import random

class Car:
    def __init__(self):
        self.generator = random.Random()

    def accelerate(self):
        random_num = self.generator.randint(50, 100)
        speed = random_num
        print(f"The speed of the car is {speed} mph")

    def apply_brakes(self):
        random_num = self.generator.randint(20, 40)
        speed = random_num
        print(f"The speed of the car is {speed} mph after applying the brakes")

    def assign_driver(self, driver_name):
        print(f"{driver_name} is driving the car")

هنا ، قمنا بإنشاء ملف Car فئة بثلاث طرق accelerate(), apply_brakes() و assign_driver(). قمنا باستيراد ملف random الوحدة النمطية واستخدامها لتوليد الأرقام التي تحدد سرعة السيارة بعد تسريعها وتشغيل الفرامل. ال assign_driver() طريقة عرض اسم سائق السيارة.

بعد ذلك ، يتعين علينا إنشاء خدمة أو فئة ملائمة ترغب في التعاون مع فئة العميل Car. قم بإنشاء فئة دراجات بخارية مثل هذه واحفظها في مجلدك باسم motorcycle.py:

import random

class Motorcycle:
    def __init__(self):
        self.generator = random.Random()

    def rev_throttle(self):
        random_num = self.generator.randint(50, 100)
        speed = random_num
        print(f"The speed of the motorcycle is {speed} mph")

    def pull_brake_lever(self):
        random_num = self.generator.randint(20, 40)
        speed = random_num
        print(
            f"The speed of the motorcycle is {speed} mph after applying the brakes")

    def assign_rider(self, rider_name):
        print(f"{rider_name} is riding the motorcycle")  

فئة الخدمة ، Motorcycle تم إنشاؤه أعلاه بثلاث طرق rev_throttle(), pull_brake_lever()و assign_rider(). لاحظ الفرق بين طرق الخدمة وفئة العميل على الرغم من وظائفهم المتشابهة. ال accelerator() طريقة تزيد من سرعة السيارة بينما rev_throttle() طريقة تزيد من سرعة الدراجة النارية. على نفس المنوال، apply_brakes() و pull_brake_lever() يستخدم الفرامل في المركبات المعنية. وأخيرا، فإن assign_driver() و assign_rider() طرق تعيين مشغل السيارة.

بعد ذلك ، دعنا ننشئ فصلًا للوصول إلى هذه الطرق المختلفة. أولاً ، أضف ملف __init.py__ في نفس المجلد الذي قمت بإنشائه car.py و motorcycle.py:

touch __init__.py

الآن أضف الكود التالي في ملف جديد drive.py:

from car import Car
from motorcycle import Motorcycle
import traceback

if __name__ == '__main__':
    car = Car()
    bike = Motorcycle()

    print("The Motorcyclen")
    bike.assign_rider("Subodh")
    bike.rev_throttle()
    bike.pull_brake_lever()
    print("n")

    print("The Carn")
    car.assign_driver("Sushant")
    car.accelerate()
    car.apply_brakes()
    print("n")

    print("Attempting to call client methods with the service objectn")

    try:
        bike.assign_driver("Robert")
        bike.accelerate()
        bike.apply_brakes()
    except AttributeError:
        print("Oops! bike object cannot access car methods")
        traceback.print_exc()

هذا البرنامج النصي الذي ينشئ كائنات العميل والخدمة. نقوم أولاً باستيراد ملف Car و Motorcycle الطبقات وخلق الأشياء معهم. ثم نستدعي الطرق من bike موضوع (Motorcycle صف دراسي). بعد ذلك ، نستدعي طرق car موضوع (Car صف دراسي). عند التنفيذ ، ستعمل جميع التعليمات البرمجية المذكورة حتى الآن.

ومع ذلك ، يظهر استثناء عندما نحاول استدعاء عمليات Car فئة مع bike هدف. عندما نقوم بتشغيل هذا البرنامج النصي:

The Motorcycle

Subodh is riding the motorcycle
The speed of the motorcycle is 91 mph
The speed of the motorcycle is 37 mph after applying the brakes


The Car

Sushant is driving the car
The speed of the car is 59 mph
The speed of the car is 33 mph after applying the brakes


Attempting to call client methods with the service object

Oops! bike object cannot access car methods
Traceback (most recent call last):
  File "drive.py", line 24, in 
    bike.assign_driver("Robert")
AttributeError: 'Motorcycle' object has no attribute 'assign_driver'

في هذه الحالة ، يمكننا تعديل ملف Motorcycle الطبقة أو drive.py البرنامج النصي لاستخدام الأساليب الصحيحة. ومع ذلك ، في كثير من الحالات ، قد لا نتمكن من الوصول إلى الكود المصدري للعميل أو فئة الخدمة. أيضا ، هذا مثال بسيط. مع العملاء والخدمات الأكبر حجمًا ، قد لا يكون من الممكن إعادة بناء أي منهما في حالة كسر التوافق مع الأنظمة الأخرى.

بدلاً من ذلك ، يمكننا استخدام محول لسد فجوة التوافق بين كود العميل وكائن الخدمة الخاص بنا.

استخدام المحولات لحل مشكلة عدم التوافق

في ملف جديد ، motorcycle_adapter.py، أضف الفئة التالية:

class MotorcycleAdapter:

    def __init__(self, motorcycle):
        self.motorcycle = motorcycle

    def accelerate(self):
        self.motorcycle.rev_throttle()

    def apply_brakes(self):
        self.motorcycle.pull_brake_lever()

    def assign_driver(self, name):
        self.motorcycle.assign_rider(name)

ولقد خلقنا MotorcycleAdapter فئة ، والتي تقوم بإنشاء مثيل لها مع كائن خدمة (motorcycle). يقوم المحول بتنفيذ طرق العميل وهي accelerate(), apply_brakes() و assign_driver(). داخل جسد accelerate() الطريقة ، لقد استخدمنا motorcycle مثيل كائن الخدمة لاستدعاء rev_throttle() طريقة الخدمة. وبالمثل ، تستخدم الطرق الأخرى الطرق المقابلة لـ Motorcycle فئة.

الآن ، دعنا نحدث drive.py حتى نتمكن من استخدام المحول في try/except كتلة:

from car import Car
from motorcycle import Motorcycle
from motorcycle_adapter import MotorcycleAdapter 
import traceback

if __name__ == '__main__':
    car = Car()
    bike = Motorcycle()
    bike_adapter = MotorcycleAdapter(bike) 

    ...

    try:
        print("Attempting to call client methods with the service object using an adaptern")
        bike_adapter.assign_driver("Robert")
        bike_adapter.accelerate()
        bike_adapter.apply_brakes()
    except AttributeError:
        print("Oops! bike object cannot access car methods")
        traceback.print_exc()

هنا،bike_adapter هو كائن من MotorcycleAdapter صف دراسي. قمنا بتزويد bike يعترض على MotorcycleAdapter منشئ فئة. يمنحنا تنفيذ هذا البرنامج النصي المخرجات التالية:

تحقق من دليلنا العملي العملي لتعلم Git ، مع أفضل الممارسات ، والمعايير المقبولة في الصناعة ، وورقة الغش المضمنة. توقف عن أوامر Googling Git وفي الواقع تعلم ذلك!

The Motorcycle

Subodh is riding the motorcycle
The speed of the motorcycle is 88 mph
The speed of the motorcycle is 35 mph after applying the brakes


The Car

Sushant is driving the car
The speed of the car is 91 mph
The speed of the car is 24 mph after applying the brakes


Attempting to call client methods with the service object

Attempting to call client methods with the service object using an adapter

Robert is riding the motorcyle
The speed of the motorcycle is 67 mph
The speed of the motorcycle is 25 mph after applying the brakes

دون الحاجة إلى تعديل الأساسي Motorcycle الفصل ، يمكننا جعله يعمل مثل أ Car باستخدام محول!

إيجابيات وسلبيات نمط تصميم المحول

مزايا أنماط المحول هي:

  • يمكننا تحقيق اقتران منخفض بين فئة المحول وفئة العميل.
  • يمكننا إعادة استخدام فئة المحول لدمج العديد من فئات الخدمة في التطبيق.
  • يمكننا زيادة مرونة البرنامج عن طريق إدخال محولات متعددة دون التدخل في كود العميل

عيوب نمط المحول هي:

  • يزداد تعقيد البرنامج مع إضافة فئة المحول وفئة الخدمة.
  • هناك زيادة في النفقات العامة في البرنامج حيث يتم إعادة توجيه الطلبات من فئة إلى أخرى.
  • يستخدم نمط المحول (محول الفئة) العديد من الوراثة ، والتي قد لا تدعمها جميع لغات البرمجة.

وفي الختام

في هذه المقالة ، تعرفنا على نمط تصميم المحول وأنواعه والمشكلات التي يتم حلها. قمنا بتطبيق نمط المحول في Python حتى نتمكن من التفاعل مع ملف Motorcycle كائن ، مثل أ Car باستخدام محول حتى لا تتغير واجهة كل فئة.

الطابع الزمني:

اكثر من ستاكابوز