اذهب إلى المحتوى

السؤال

Recommended Posts

  • 1
نشر (معدل)
اقتباس

مفهوم تعدد الأشكال (Polymorphism)

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

# len هنا قمنا بتمرير سلسلة نصية للدالة
print(len("ali"))
# len للدالة list بينما هنا قمنا بتمرير قائمة
print(len([20, 30]))

خرج البرنامج:

3
2

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

def add(a, b, c = 0): 
	return a + b+c
print(add(10, 33))
print(add(20, 2, 5))

حيث قمنا بتعريف دالة add يمكنها جمع عددين أو 3 أعداد (الوسيط c يأخذ القيمة 0 بشكل افتراضي (أي في حال لم تمرر لها قيمة) وهي قيمة محايدة لعملية الجمع)، ثم قمنا باستدعاء الدالة مرتين، الأولى لجمع عددين والثانية لجمع 3 أعداد، هذا مثال آخر بسيط لتعددية الأشكال.
مثال آخر لتعددية الأشكال لكن هذه المرة مع الأصناف:

# تعرف صنف يمثل بلد
class Syria():
	def capital(self):
		print("Damascus")
	def language(self):
		print("Arabic")
# تعريف صنف يمثل بلد آخر
class England():
	def capital(self):
		print("London")
	def language(self):
		print("English")
# إنشاء كائن يمثل البلد الأول
obj_sy = Syria()
# إنشاء غرض ثاني يمثل البلد الثاني
obj_eng = England()
# obj_eng ومرة إلى الكائن obj_sy يشير مرةً إلى الكائن  country الآن سنجعل متغير الحلقة 
# وفي كل مرة سيستدعي نفس الدوال
# وهذه صورة أخرى من أشكال تعددية الأشكال
for country in (obj_sy, obj_eng):
	country.capital()
	country.language()


- الآن سنعطي مثالاً آخر لتعددية الأشكال لكن هذه المرة مع الوراثة ومع لغة أخرى هي الجافا، حيث أن أحد الاستخدامات الشائعة لمفهوم تعددية الأشكال يحدث عندما يكون لدينا مرجع من صف أب (نسميه مقبض)يشير إلى كائن من صف ابن.
لنفرض مثلاً لدينا شاحنة ونريد نقل مجموعة سيارات بحيث كل شاحنة تتسع ل 10  سيارات ، وتنقل نوع واحد من السيارات ( يمكن تشبيه الشاحنة بمصفوفة تضم عناصر من نمط واحد ).
لنفرض لدينا نوعين من السيارات نريد أن ننقلهم 4:BMW   و  4:AUDI
حسب الشروط المفروضة سنحتاج شاحنتين في كل واحدة سنضع 4  من نفس النوع ..
الفكرة أن الشاحنة الواحدة (مصفوفة ) لا تحمل نوعين لكنها  تتسع للعدد الكلي ، أي أننا قمنا بعملية نقل صحيحة لكنها مكلفة ( حجزنا شاحنة ويوجد أماكن فارغة بالأولى  + ماذا  لو كان لدينا أكثر من نوعين .. )
الحل : يجب أن نبحث عن شاحنة ( مصفوفة)  تحمل النوعين، ونعلم أن المصفوفة لا تحمل الا نوع واحد، ما العمل؟
هنا تأتي " تعددية الأشكال" بأن نعرف صف أب للصفين السابقين وليكن Carونرث منه الصفين BMW و AUDI ونأخذ مصفوفة مقابض من Car ( نمط واحد ) وكل عنصر (مقبض) نجعله يشير الى الكائن المطلوب ( BMW أو AUDI ).
وهكذا نكون قد حللنا المشكلة و خزنا كائنات من صفوف مختلفة بمصفوفة واحدة
مثال : (يمكن نسخ الكود وتنفيذه لملاحظة النتائج):

package javaapplication29;
class Car {
void type () { System.out.println("car");}
}
class BMW extends Car {
@Override
void type () { System.out.println("BMW");}
}
class AUDI extends Car {
@Override
void type () { System.out.println("AUDI");}
}
public class JavaApplication29 {
public static void main(String[]args ){
Car[]c =new Car[8];
//نعبئ أربع سيارات BMW
for( int  i=0; i<4 ; ++i )
    c[i] = new BMW();
//نعبئ أربع سيارات AUDI
for( int  i=4; i<8 ; ++i )
    c[i] = new AUDI();
//تعليمة طباعة للتأكد من أنه تم تعبئة النوعين  
for( int  i=0; i<8 ; ++i ) c[i].type();
}
}

مثال آخر:

// الفئة الأم (الأشكال)
class Shapes {
  public void area() {
    System.out.println("The formula for area of ");
  }
}

// فئة المثلثات
class Triangle extends Shapes {
  public void area() {
    System.out.println("Triangle is ½ * base * height ");
  }
}
// فئة الدوائر
class Circle extends Shapes {
  public void area() {
    System.out.println("Circle is 3.14 * radius * radius ");
  }
}
class Main {
  public static void main(String[] args) {
    Shapes myShape = new Shapes();  //  إنشاء كائن الأشكال
    Shapes myTriangle = new Triangle();  // إنشاء كائن المثلثات
    Shapes myCircle = new Circle();  //  إنشاء كائن الدوائر  
    myShape.area();
    myTriangle.area();
    myShape.area();
    myCircle.area();
  }

نلاحظ أنه في كل كائن نستعمل الدالة ()area بشكل مختلف حسب طبيعة الكائن و هذا ما يسمى ب  polymorphism.

- الآن سأعطي مثالاً آخر لتعددية الأشكال لكن بلغة برمجية أخرى هي لغة الأسس (مشابهة جداً للغة ال C):
لتحقيق مبدأ تعددية الأشكال مع الأصناف في هذه اللغة يجب أن نقوم بتعريف الدوال كمؤشرات، وهذا يتم من خلال إضافة الكلمة المفتاحية as_ptr للأمر handler (بشكل مشابه للكلمة المفتاحية virtual في c++).
فلنفترض أن لدينا الصنف التالي:

class A {
  handler this.set(i: Int) as_ptr { ... }
}

في التعريف أعلاه، سيضيف المترجم إلى الصنف A مؤشراً على الدالة set. وهذا يُمكّن الكائنات المشتقة من A (التي تقوم بوراثتها) من تخصيص الدالة عبر تغيير قيمة المتغير. مثلاً:

class B {
  @injection def a: A;
  handler this.set(i: Int) set_ptr { ... }
}

في هذا التعريف الصنف B يشتق من الصنف A ثم يغير مؤشر الدالة set (باستخدام الكلمة المفتاحية set_ptr) لتعريف خاص ب B.
الآن لو كان هناك دالة تستلم سنداً أو مؤشراً على A فيمكنك إعطاؤها سنداً ل B وستراه الدالة على أنه صنف A مع دالة set خاصة ب B.
قد تكون الأمور غامضة قليلاً، لكنها ستتضح في المثال التالي...
قمنا بتعريف صنف اسمه Country يحوي 3 دوال لم يحدد متنها (body).
بعدها قمنا بتعريف صنف اسمه Canda و صنف اسمه Syria يرثان من الصنف Country و كل منهما يحتوي تعريفاً خاصاً لنفس الدوال الموجودة في الصنف الأب Country.
بعدها قمنا بإنشاء دالة اسمها printCountryInfo مهمتها استدعاء جميع الدوال الموجودة في الكائن الذي نمرره لها بشرط أن يكون هذا الكائن قد تم إنشاؤه من صنف يرث من الصنف Country، حيث أن هذه الدالة تستلم سنداً من الصنف الأب.
في النهاية قمنا بإنشاء كائن من الصنف Canda و كائن من الصنف Syria و تمرير كل كائن منهما للدالة printCountryInfo.

import "Srl/Console.alusus"
use Srl.Console;
// تعريف صنف يمثل بلد
class Country
{
	// دالة سنستخدمها لطباعة اسم البلد
    handler this.name() as_ptr;
	// دالة سنستخدمها لطباعة العاصمة
    handler this.capital() as_ptr;
	// دالة سنستخدمها لطباعة اللغة
	handler this.language() as_ptr;		
}
// تعريف صنف يمثل بلد محدد هو كندا
class Canda
{
        // country سنقوم الآن بوراثة الصنف 
	    @injection def country: Country;
        // تعريفاً مخصصاً Country الآن سنقوم بتعريف الدوال الموجودة في الصنف
        handler (this:Country).name() set_ptr{
        	print("Country: Canda\n")
        }
        handler (this:Country).capital() set_ptr{
        	print("Capital: Ottawa\n")
        }
        handler (this:Country).language() set_ptr{
        	print("Language: English\n")
        }		
}
// تعريف صنف آخر يمثل بلد محدد هو سوريا
class Syria
{
     	@injection def country: Country;
        handler (this:Country).name() set_ptr{
        	print("Country: Syria\n")
        }
        handler (this:Country).capital() set_ptr{
        	print("Capital: Damascus\n")
        }
        handler (this:Country).language() set_ptr{
        	print("Language: Arabic\n")
        }		
}
// Country دالة تقوم باستلام سند من الصنف 
// ثم في متن هذه الدالة سنقوم باستخدام السند للوصول إلى الدوال
function printCountryInfo(re:ref[Country]){
	re.name() // تؤدي إلى طباعة اسم بلد
	re.capital() // العاصمة
	re.language() // اللغة
	print("\n********************\n")
}
// Canda إنشاء كائن من  الصنف 
def obj1: Canda;
// لطباعة معلومات هذا البلد printCountryInfo سنقوم الآن بتمريره إلى الدالة 
printCountryInfo(obj1)
// Syria سنكرر الآن نفس الأمر لكن مع كائن من الصنف 
def obj2: Syria;
printCountryInfo(obj2)
/*
Country: Canda
Capital: Ottawa
Language: English

********************
Country: Syria
Capital: Damascus
Language: Arabic

********************
*/

هكذا نكون قد كتبنا دالة بسيطة تحقق مبدأ تعددية الأشكال.
مقال ذات صلة:

سؤال ذات صلة:

 

تم التعديل في بواسطة Ali Haidar Ahmad
  • 0
نشر

الجواب ان تعدد الأشكال يعني العديد من الأشكال.
تعدد الأشكال يسمح لكائن بالتصرف بطرق متعددة.

انظر الى المثال التالي

Public class Manipulation(){ //كلا الاب
  public void add(){
  }
}

public class Addition extends Manipulation(){ // كلاس الابن
  public void add(){
  }

  public static void main(String args[]){
  Manipulation addition = new Addition(); // انشأنا كائن من الكلاس الابن ورجعناه من نوع الاب
  addition.add(); // عند استدعاء هذه الدالة يتجاوز دالة الاب ويستدعي دالة الابن
  }
}

 

  • 0
نشر

تعدد الأشكال(polymorphism) يعني أن يتم تعامل مع الكائن أو الموروثات منه ويتم إستخدامه في العديد من الdesign patterns فعلى سبيل المثال  في لغة جافا يوجد كلا الصنفين bufferedInputStream و DataInputStream , كلاهما موروثان من الصنف FilterInputStream ولكن كلًا منهما له خصائص مختلفة فعلى سبيل المثال الصنف الأول يتم إستخدامه لكتابة النصوص بشكلٍ إفتراضي على عكس الصنف الثاني الذي بشكلٍ إفتراضي يتم إستخدامه لكتابة الأنواع البدائية من البيانات مثل Integer, byte 

إن أردنا إنشاء دالة تقوم بإستقبال أي صنف من الإثنين بدون عمل Overload يمكننا وقتها إستخدام خاصية تعدد الأشكال عبر تعريف الدالة أنها تستقبل الصنف الأب وبالتالي يمكن إستقبال أيًا من الأبناء كما في الشفرة التالية 

public void manibulateStream(FilterInputstream filter){
///your code
}

FilterInputstream datain =new DataInputStream();
FilterInputstream bufferedin = new BufferedInputStream();

manibulateStream(datain);
manibulateStream(bufferedin);

 

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...