תבנית עיצוב מתאם ב- Python

מבוא

אל האני דפוס עיצוב מתאם הוא פופולרי דפוס עיצוב מבני משמש בהנדסת תוכנה. מדריך זה בוחן כיצד אנו יכולים ליישם את דפוס עיצוב המתאם ב-Python.

תבניות עיצוב הם פתרונות דמויי תבנית - למעשה מתכונים לפתרון בעיות חוזרות ונפוצות בפיתוח תוכנה. תבנית המתאם מבוססת על הרעיון של מתאם בעולם האמיתי! לדוגמה, למטען של מחשב נייד עשוי להיות תקע 3 פינים בקצהו, אך ייתכן שהשקע בקיר יהיה רק ​​שקע 2 פינים. כדי לחבר מטען 3 פינים לשקע זה, נצטרך מתאם, שמקבל תקע 3 פינים, ו מסתגל הממשק לתוך 2 פינים שקע.

מטען 2 פינים ומטען 3 פינים יש אותה פונקציה בסיסית (להעביר חשמל מהשקע למחשב הנייד), אבל יש צורה אחרת, ואפשר בקלות להסתגל לתוך השני. בכל פעם שיש לך רכיבי תוכנה עם אותה פונקציה בסיסית אבל צורות שונות, אתה יכול ליישם את תבנית העיצוב של המתאם.

תבנית המתאם פועלת לפי העיקרון המדויק הזה. זה מאפשר לשני ממשקים לא תואמים לעבוד יחד מבלי לשנות את החלקים הפנימיים של כל רכיב. זה מושג על ידי התאמת ממשק אחד, למשנהו, חיצונית.

בואו נסתכל על כמה מינוחים בסיסיים לפני שנצלול עמוק יותר לתוך העולם של דפוסי מתאם:

  • ממשק לקוח: ממשק המפרט את הפונקציות שעל הלקוח ליישם.
  • לקוח: מחלקה המיישמת את ממשק הלקוח.
  • Adaptee/שירות: המחלקה הבלתי תואמת שצריכה לשתף פעולה עם ממשק הלקוח.
  • מַתאֵם: המעמד המאפשר את שיתוף הפעולה בין השירות ללקוח.

סוגים שונים של דפוסי מתאם

ניתן ליישם את דפוס עיצוב המתאם בשתי דרכים שונות:

מתאם אובייקט

בשיטה זו, מחלקת המתאם מיישמת את השיטות מממשק הלקוח. לפיכך, אובייקט הלקוח ואובייקט המתאם תואמים זה לזה. אובייקט השירות יוצר א has-a קשר עם אובייקט המתאם כלומר אובייקט השירות שייך לאובייקט המתאם.

אנו יודעים שמעמד השירות אינו תואם ללקוח. מחלקת המתאם עוטפת את אובייקט השירות על ידי מופע עצמו עם אובייקט זה. כעת, ניתן לגשת לאובייקט השירות דרך אובייקט המתאם, מה שמאפשר ללקוח ליצור איתו אינטראקציה.

אנו יכולים ליישם את מתאם האובייקטים בכל שפות התכנות המודרניות.

מתאם כיתה

בשיטה זו, למתאם יש is-a הקשר עם מעמד השירות. בתרחיש זה, המתאם מיישם את השיטות הנדרשות על ידי הלקוח, אך הוא יורש ממספר מתאמים, מה שנותן לו את היכולת לקרוא ישירות לפונקציות הבלתי תואמות שלהם. החיסרון הגדול ביותר בווריאציה זו הוא שאנו יכולים להשתמש בה רק בשפות התכנות התומכות בהורשה מרובה של מחלקות.

יישום דפוס עיצוב המתאם ב-Python

בסעיף שלהלן, ניישם את תבנית עיצוב המתאם ב-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() שיטות להקצות את מפעיל הרכב.

לאחר מכן, בואו ניצור מחלקה כדי לגשת לשיטות השונות הללו. ראשית, הוסף an __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 class, אשר מבצע את עצמו עם אובייקט שירות (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, עם שיטות עבודה מומלצות, סטנדרטים מקובלים בתעשייה ודף רמאות כלול. תפסיק לגוגל פקודות 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 באמצעות מתאם!

יתרונות וחסרונות של דפוס עיצוב מתאם

היתרונות של דפוסי מתאם הם:

  • אנו יכולים להשיג צימוד נמוך בין מחלקת המתאמים למחלקת הלקוח.
  • אנו יכולים לעשות שימוש חוזר במחלקת המתאם כדי לשלב מספר מחלקות שירות באפליקציה.
  • אנו יכולים להגביר את הגמישות של התוכנית על ידי הצגת מתאמים מרובים מבלי להפריע לקוד הלקוח

החסרונות של דפוס מתאם הם:

  • מורכבות התוכנית גדלה עם הוספת מחלקת מתאם ומחלקת שירות.
  • ישנה עלייה בתקורה בתוכנית מכיוון שהבקשות מועברות מכיתה אחת לאחרת.
  • Adapter Pattern (מתאם מחלקה) משתמש במספר ירושות, אשר ייתכן שכל שפות התכנות אינן תומכות בהן.

סיכום

במאמר זה למדנו על דפוס עיצוב המתאם, סוגיו והבעיות שהם פותרים. הטמענו את תבנית המתאם ב-Python כדי שנוכל ליצור אינטראקציה עם a Motorcycle חפץ, כמו א Car אובייקט באמצעות מתאם כך שהממשק של כל מחלקה לא ישתנה.

בול זמן:

עוד מ Stackabuse