التركيب مقابل الوراثة
جزء من قسم Object Oriented Programming في رحلة Python على Coddy — الدرس 37 من 64.
توفر البرمجة كائنية التوجه نهجين رئيسيين لإعادة استخدام الكود: الوراثة (علاقة "is-a") والتركيب (علاقة "has-a").
إليك مثال على الوراثة التي تنشئ علاقة "is-a":
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
return f"{self.name} is eating"
class Dog(Animal): # Dog هو Animal
def bark(self):
return "Woof!"
dog = Dog("Buddy")
print(dog.eat()) # دالة موروثة (Inherited method)
print(dog.bark()) # دالة خاصة (Own method)إليك مثال على التركيب (composition) الذي ينشئ علاقة "لديه" (has-a):
class Engine:
def start(self):
return "Engine started"
def stop(self):
return "Engine stopped"
class Car: # السيارة "لديها" محرك
def __init__(self):
self.engine = Engine() # تركيب
def start(self):
return self.engine.start()
car = Car()
print(car.start()) # يستخدم المحرك المركبقارن بين كلا النهجين بمثال أكثر تعقيداً:
# نهج الوراثة
class Bird:
def move(self):
return "Flying"
class Duck(Bird):
def quack(self):
return "Quack!"
# نهج التركيب
class FlyBehavior:
def move(self):
return "Flying"
class SwimBehavior:
def move(self):
return "Swimming"
class VersatileDuck:
def __init__(self):
self.fly_behavior = FlyBehavior()
self.swim_behavior = SwimBehavior()
def fly(self):
return self.fly_behavior.move()
def swim(self):
return self.swim_behavior.move()
def quack(self):
return "Quack!"اختبر كلا النهجين:
# الوراثة
duck1 = Duck()
print(duck1.move()) # طيران
print(duck1.quack()) # كواك!
# التركيب
duck2 = VersatileDuck()
print(duck2.fly()) # طيران
print(duck2.swim()) # سباحة
print(duck2.quack()) # كواك!المخرجات:
Buddy is eating
Woof!
Engine started
Flying
Quack!
Flying
Swimming
Quack!الاختلافات الرئيسية:
الوراثة (Inheritance):
- ارتباط وثيق بين الأب (parent) والابن (child)
- علاقة "من نوع" (Is-a)
- التغييرات في الأب تؤثر على جميع الأبناء
- الأفضل للعلاقات الهرمية الحقيقية
التركيب (Composition):
- ارتباط ضعيف (Loose coupling) بين الكائنات
- علاقة "يحتوي على" (Has-a)
- أكثر مرونة - يمكن تغيير السلوك في وقت التشغيل (runtime)
- أسهل في الاختبار والتعديل
نقطة رئيسية: استخدم الوراثة (inheritance) عندما يكون لديك علاقة "is-a" حقيقية. استخدم التركيب (composition) عندما تحتاج إلى المرونة والارتباط الضعيف (loose coupling). يقترح مبدأ "التركيب بدلاً من الوراثة" (composition over inheritance) تفضيل التركيب في معظم الحالات نظراً لمرونته وقابليته للصيانة.
التحدي
متوسطفي هذا التحدي، ستقوم بتنفيذ نظام مكتبة وسائط باستخدام أنماط الوراثة (inheritance) والتركيب (composition).
تحتاج إلى تعديل الملفات التالية، باتباع تعليقات TODO داخل كل منها:
media.py،book.py،movie.py،musicalbum.py- لتنفيذ الوراثةmediaitem.py،bookcomposition.py،moviecomposition.py،musicalbumcomposition.py- لتنفيذ التركيب
يجب أن يحتوي كل نوع من الوسائط على:
- سمات العنوان (Title)، والمنشئ (creator) (المؤلف/المخرج/الفنان)، والسنة (year)
- طريقة
display_info()مناسبة
ورقة مرجعية
تقدم البرمجة كائنية التوجه نهجين رئيسيين لإعادة استخدام الكود: الوراثة (علاقة "is-a") والتركيب (علاقة "has-a").
مثال على الوراثة:
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
return f"{self.name} is eating"
class Dog(Animal): # Dog "is an" Animal
def bark(self):
return "Woof!"
dog = Dog("Buddy")
print(dog.eat()) # تابع موروث
print(dog.bark()) # تابع خاصمثال على التركيب:
class Engine:
def start(self):
return "Engine started"
class Car: # Car "has an" Engine
def __init__(self):
self.engine = Engine() # تركيب
def start(self):
return self.engine.start()
car = Car()
print(car.start()) # يستخدم المحرك المركبالاختلافات الرئيسية:
الوراثة:
- ارتباط وثيق بين الفئة الأب والفئة الابن
- علاقة "Is-a"
- التغييرات في الفئة الأب تؤثر على جميع الفئات الأبناء
- الأفضل للعلاقات الهرمية الحقيقية
التركيب:
- ارتباط ضعيف بين الكائنات
- علاقة "Has-a"
- أكثر مرونة - يمكن تغيير السلوك في وقت التشغيل
- أسهل في الاختبار والتعديل
استخدم الوراثة لعلاقات "is-a" الحقيقية. استخدم التركيب للمرونة والارتباط الضعيف. يقترح مبدأ "التركيب بدلاً من الوراثة" تفضيل التركيب في معظم الحالات.
جرّب بنفسك
from media import Media
from book import Book
from movie import Movie
from musicalbum import MusicAlbum
from mediaitem import MediaItem
from bookcomposition import BookComposition
from moviecomposition import MovieComposition
from musicalbumcomposition import MusicAlbumComposition
# معالج حالات الاختبار الشاملة
test_case = input()
def test_inheritance_basic():
book = Book("The Hobbit", "J.R.R. Tolkien", 1937)
movie = Movie("The Matrix", "Wachowski Sisters", 1999)
album = MusicAlbum("Abbey Road", "The Beatles", 1969)
assert book.display_info() == "Book: The Hobbit by J.R.R. Tolkien (1937)"
assert movie.display_info() == "Movie: The Matrix directed by Wachowski Sisters (1999)"
assert album.display_info() == "Music Album: Abbey Road by The Beatles (1969)"
def test_composition_basic():
book_comp = BookComposition("Dune", "Frank Herbert", 1965)
movie_comp = MovieComposition("Inception", "Christopher Nolan", 2010)
album_comp = MusicAlbumComposition("Thriller", "Michael Jackson", 1982)
assert book_comp.display_info() == "Book: Dune by Frank Herbert (1965)"
assert movie_comp.display_info() == "Movie: Inception directed by Christopher Nolan (2010)"
assert album_comp.display_info() == "Music Album: Thriller by Michael Jackson (1982)"
def test_inheritance_relationships():
book = Book("Test Book", "Test Author", 2000)
movie = Movie("Test Movie", "Test Director", 2001)
album = MusicAlbum("Test Album", "Test Artist", 2002)
assert isinstance(book, Book)
assert isinstance(book, Media)
assert isinstance(movie, Movie)
assert isinstance(movie, Media)
assert isinstance(album, MusicAlbum)
assert isinstance(album, Media)
def test_attribute_access():
# اختبار نهج الوراثة
book = Book("Test Book", "Test Author", 2000)
assert book.title == "Test Book"
assert book.creator == "Test Author"
assert book.year == 2000
# اختبار نهج التركيب (Composition)
book_comp = BookComposition("Test Book", "Test Author", 2000)
assert book_comp.media.title == "Test Book"
assert book_comp.media.creator == "Test Author"
assert book_comp.media.year == 2000
def test_polymorphism():
media_list = [
Book("Book1", "Author1", 2001),
Movie("Movie1", "Director1", 2002),
MusicAlbum("Album1", "Artist1", 2003)
]
assert media_list[0].display_info() == "Book: Book1 by Author1 (2001)"
assert media_list[1].display_info() == "Movie: Movie1 directed by Director1 (2002)"
assert media_list[2].display_info() == "Music Album: Album1 by Artist1 (2003)"
def test_edge_cases():
# نصوص فارغة
book = Book("", "", 0)
assert book.display_info() == "Book: by (0)"
# رموز خاصة - تم إصلاح الخطأ البرمجي هنا
movie = Movie("Test\"Movie", "Test\\nDirector", -1)
assert movie.display_info() == "Movie: Test\"Movie directed by Test\\nDirector (-1)"
# سنوات قصوى
album = MusicAlbum("Test Album", "Test Artist", 9999)
assert album.display_info() == "Music Album: Test Album by Test Artist (9999)"
def test_stress():
# إنشاء العديد من كائنات الوسائط
books = [Book(f"Book{i}", f"Author{i}", 2000+i) for i in range(100)]
movies = [Movie(f"Movie{i}", f"Director{i}", 2000+i) for i in range(100)]
albums = [MusicAlbum(f"Album{i}", f"Artist{i}", 2000+i) for i in range(100)]
for i, book in enumerate(books):
assert book.display_info() == f"Book: Book{i} by Author{i} ({2000+i})"
for i, movie in enumerate(movies):
assert movie.display_info() == f"Movie: Movie{i} directed by Director{i} ({2000+i})"
for i, album in enumerate(albums):
assert album.display_info() == f"Music Album: Album{i} by Artist{i} ({2000+i})"
# تشغيل الاختبار المناسب بناءً على المدخلات
if test_case == "default_test" or test_case == "":
test_inheritance_basic()
test_composition_basic()
print("All tests passed!")
elif test_case == "inheritance_test":
test_inheritance_basic()
test_inheritance_relationships()
print("Inheritance tests passed!")
elif test_case == "composition_test":
test_composition_basic()
print("Composition tests passed!")
elif test_case == "polymorphism_test":
test_polymorphism()
print("Polymorphism tests passed!")
elif test_case == "attribute_test":
test_attribute_access()
print("Attribute tests passed!")
elif test_case == "edge_cases":
test_edge_cases()
print("Edge case tests passed!")
elif test_case == "stress_test":
test_stress()
print("Stress tests passed!")يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsمعامل selfMethodsAttributesدالة البناء (__init__)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةدالة ()superإعادة تعريف الدوال (Method Overriding)الوراثة المتعددةترتيب استدعاء الدوال (Method Resolution Order)مراجعة - هيكلية الموظفين5تعدد الأشكال
مراجعة إعادة تعريف الدوالمفهوم Duck Typingالأصناف والدوال المجردةتصميم الواجهاتملخص - حاسبة الأشكال8مفاهيم OOP المتقدمة
التركيب مقابل الوراثةMixinsدوال Static و Classمزخرفات Classمديرو السياق (Context Managers)