می 28, 2019 Mostafa بدون دیدگاه

polymorphism یا چندریختی مفهومی مشترک بین زبان های شی گرا است که طی آن می توان یک فعل یا عملیات خاص را به روش های مختلف انجام داد. در زبان برنامه نویسی جاوا وقتی سخن از یک تابع چندریختی به میان می آید، منظور قابلیت و توانایی آن تابع برای انجام کارهای مختلف بر اساس آبجکتی است که به آن متعلق است.

خود واژه ی چندریختی از دو کلمه ی یونانی poly و morph تشکیل شده که هر یک به ترتیب به معنای چند و شکل می باشند. بنابراین polymorphism در کنار هم به معنای چندشکلی یا چندریختی می باشد و به معنای ساده تر هر چیز که بتواند اشکال مختلف به خود بگیرد.

در جاوا دو نوع چندریختی وجود دارد: 1. چندریختی در زمان کامپایل 2. چندریختی در زمان اجرا. در زبان جاوا با فراخوانی متدی یکسان با پارامترهای مختلف (overloading) و بازنویسی بدنه ی متد (overriding) در کلاس فرزند، می توان مفهوم چندریختی را به آسانی پیاده سازی کرد.

اگر توسعه دهنده متدی static را با پارامترهای مختلف صدا بزند/overload کند، در واقع چندریختی زمان کامپایل را پیاده سازی کرده است.

ما قصد داریم در این مبحث چندریختی زمان اجرا را پیاده سازی کنیم.
شرح مفهوم Upcasting (تبدیل کلاس سطح پایین تر یا فرزند به کلاس سطح بالاتر یا پدر)

زمانی که آّبجکتی (reference variable) از کلاس پدر آبجکتی از کلاس فرزند را در خود نگه داشته و به آن اشاره کند، در برنامه نویسی شی گرا به آن upcasting می گویند. مثال :

class A{}  
class B extends A{}  
A a=new B();

مثال کاربردی از پیاده سازی مفهوم چندریختی در زمان اجرا

در مثال پیشرو دو کلاس به نام های Bike و Splendar ایجاد می کنیم. Splendar از کلاس Bike ارث بری کرده و متد run() آن را داخل خود بازنویسی (override) می کند. همان طور که در زیر مشاهده می کنید، متد run() را از طریق متغیری از جنس کلاس پدر (Bike) یا متغیر اشاره گر به کلاس پدر فراخوانی می کنیم. از آنجایی که متغیر b از جنس کلاس پدر (Bike) نمونه ای از کلاس Splender را در خود نگه داشته و متد run() داخل کلاس فرزند (Splender) بازنویسی شده است، متد کلاس فرزند در زمان اجرای برنامه فراخوانی می شود.

همچنین به این خاطر که jvm (دستگاه مجاری جاوا که بستر اجرای برنامه را فراهم می کند) فراخوانی متدها را انجام می دهد، نه کامپایلر، به این نوع پیاده سازی چندریختی در زمان اجرا یا پیاده سازی مفهوم چندریختی در زمان اجرای برنامه می گویند.

class Bike{  
  void run(){System.out.println("running");}  
}  
class Splender extends Bike{  
  void run(){System.out.println("running safely with 60km");}  
  public static void main(String args[]){  
    Bike b = new Splender();//upcasting  
    b.run();  
  }  
}

خروجی : running safely with 60km.

پیاده سازی چند ریختی در زمان اجرا : مثال Bank

¬سناریویی را در نظر بگیرید که در آن Bank یک کلاس ساده است که نرخ پرداخت سود ماهیانه را خروجی می دهد. نرخ پرداخت سود ممکن است با توجه به بانک (آبجکت) مربوطه متفاوت باشد. برای مثال بانک های SBI، ICICI و AXIS هر یک به ترتیب مقادیر 8.4%، 7.3% و 9.7% را به عنوان نرخ پرداخت سود ماهیانه درنظر می گیرند.

 

نکته : این مثال در مبحث overriding نیز پوشش داده شده است با این تفاوت که در آن هیچ upcasting و تبدیل از کلاس فرزند به پدر پیاده سازی نمی شود.

class Bank{  
float getRateOfInterest(){return 0;}  
}  
class SBI extends Bank{  
float getRateOfInterest(){return 8.4f;}  
}  
class ICICI extends Bank{  
float getRateOfInterest(){return 7.3f;}  
}  
class AXIS extends Bank{  
float getRateOfInterest(){return 9.7f;}  
}  
class TestPolymorphism{  
public static void main(String args[]){  
Bank b;  
b=new SBI();  
System.out.println("SBI Rate of Interest: "+b.getRateOfInterest());  
b=new ICICI();  
System.out.println("ICICI Rate of Interest: "+b.getRateOfInterest());  
b=new AXIS();  
System.out.println("AXIS Rate of Interest: "+b.getRateOfInterest());  
}  
}

خروجی :

SBI Rate of Interest: 8.4
ICICI Rate of Interest: 7.3
AXIS Rate of Interest: 9.7

پیاده سازی چندریختی در زمان اجرا: مثال Shape

class Shape{  
void draw(){System.out.println("drawing...");}  
}  
class Rectangle extends Shape{  
void draw(){System.out.println("drawing rectangle...");}  
}  
class Circle extends Shape{  
void draw(){System.out.println("drawing circle...");}  
}  
class Triangle extends Shape{  
void draw(){System.out.println("drawing triangle...");}  
}  
class TestPolymorphism2{  
public static void main(String args[]){  
Shape s;  
s=new Rectangle();  
s.draw();  
s=new Circle();  
s.draw();  
s=new Triangle();  
s.draw();  
}  
}

خروجی :

drawing rectangle...
drawing circle...
drawing triangle...

پیاده سازی polymorphism در زمان اجرا: مثال Animal

class Animal{  
void eat(){System.out.println("eating...");}  
}  
class Dog extends Animal{  
void eat(){System.out.println("eating bread...");}  
}  
class Cat extends Animal{  
void eat(){System.out.println("eating rat...");}  
}  
class Lion extends Animal{  
void eat(){System.out.println("eating meat...");}  
}  
class TestPolymorphism3{  
public static void main(String[] args){  
Animal a;  
a=new Dog();  
a.eat();  
a=new Cat();  
a.eat();  
a=new Lion();  
a.eat();  
}}

خروجی :

eating bread...
eating rat...
eating meat...

پیاده سازی چندریختی در زمان اجرا با فیلدها و متغیرهای کلاس/ Data Member

این متد است که بدنه ی آن داخل کلاس فرزند بازنویسی می شود. فیلدهای یک کلاس قابل بازنویسی نیستند و نمی توان polymorphism زمان اجرا را بر روی آن ها پیاده سازی کرد.

در مثال زیر فیلد speedlimit بین دو کلاس پدر و فرزند مشترک بوده ولی در هر کلاس دارای مقادیر متفاوت می باشد. همان طور که مشاهده می کنید از طریق آبجکت کلاس پدر (متغیر اشاره گر به کلاس پدر یا همان b) که نمونه ی کلاس فرزند را در خود نگه می دارد، به فیلد مورد نظر از کلاس فرزند (speedlimit=150) دسترسی پیدا کرده و آن را فراخوانی می کنیم. از آنجایی که در این مثال متغیر کلاس فرزند را فراخوانی می کنیم که بازنویسی نشده است، برنامه مقدار کلاس پدر را در خروجی چاپ می کند.
نکته : چندریختی در زمان اجرا با اعضای داده ای کلاس یا همان فیلدها قابل پیاده سازی نمی باشد.

class Bike{  
 int speedlimit=90;  
}  
class Honda3 extends Bike{  
 int speedlimit=150;    
 public static void main(String args[]){  
  Bike obj=new Honda3();  
  System.out.println(obj.speedlimit);//90  
}

پیاده سازی چندریختی در زمان اجرای برنامه با وراثت چند سطحی (multi-level)

در زیر مثال ساده ای که چندریختی در زمان اجرا با وراثت چند سطحی پیاده سازی شده را مشاهده می کنید:

class Animal{  
void eat(){System.out.println("eating");}  
}  
class Dog extends Animal{  
void eat(){System.out.println("eating fruits");}  
}  
class BabyDog extends Dog{  
void eat(){System.out.println("drinking milk");}  
public static void main(String args[]){  
Animal a1,a2,a3;  
a1=new Animal();  
a2=new Dog();  
a3=new BabyDog();  
a1.eat();  
a2.eat();  
a3.eat();  
}  
}

خروجی :

eating
eating fruits
drinking Milk

مثال کاربردی نهایی

class Animal{  
void eat(){System.out.println("animal is eating...");}  
}  
class Dog extends Animal{  
void eat(){System.out.println("dog is eating...");}  
}  
class BabyDog1 extends Dog{  
public static void main(String args[]){  
Animal a=new BabyDog1();  
a.eat();  
}}

خروجی :

Dog is eating

در مثال حاضر، همان طور که مشاهده می کنید از آنجایی که کلاس فرزند BabyDog متد eat از کلاس پدر (Dog) را در بدنه ی خود بازنویسی (override) نمی کند، متد eat() کلاس Dog صدا خورده شده و متن Dog is eating در خروجی چاپ می شود.


برچسب ها
نظرات

توجه : لطفاً فقط نظرات خود را از این طریق ارسال نمایید و سوالات و مشکلات خود را در انجمن سایت مطرح نمایید.

دیدگاهتان را بنویسید

برای نوشتن دیدگاه باید وارد بشوید.