چند ریختی (Polymorphism)

چند ریختی به کلاسهایی که در یک سلسله مراتب وراثتی مشابه هستند اجازه تغییر شکل و سازگاری مناسب می دهد و همچنین به برنامه نویس این امکان را می دهد که به جای ایجاد برنامه های خاص، برنامه های کلی و عمومی تری ایجاد کند. . به عنوان مثال در دنیای واقعی همه حیوانات غذا می خورند، اما روش های غذا خوردن آنها متفاوت است. در یک برنامه برای مثال ، یک کلاس به نام Animal ایجاد می کنید. بعد از ایجاد این کلاس می توانید آن را چند ریخت (تبدیل) به کلاس Bird کنید و متد Fly() را فراخوانی کنید. به مثالی درباره چند ریختی توجه کنید :

   1: package myfirstprogram;
   2: 
   3: class Animal
   4: {
   5:     public void Eat()
   6:     {
   7:         System.out.println("The animal ate!");
   8:     }
   9: }
  10: 
  11: class Dog extends Animal
  12: {
  13:     @Override
  14:     public void Eat()
  15:     {
  16:         System.out.println("The dog ate!");
  17:     }
  18: }
  19: 
  20: class Bird extends Animal
  21: {
  22:     @Override
  23:     public void Eat()
  24:     {
  25:         System.out.println("The bird ate!");
  26:     }
  27: }
  28: 
  29: class Fish extends Animal
  30: {
  31:     @Override
  32:     public void Eat()
  33:     {
  34:         System.out.println("The fish ate!");
  35:     }
  36: }
  37: 
  38: public class MyFirstProgram 
  39: {
  40:     public static void main(String[] args) 
  41:     { 
  42:         Dog myDog = new Dog();
  43:         Bird myBird = new Bird();
  44:         Fish myFish = new Fish();
  45:         Animal myAnimal = new Animal();
  46:    
  47:         myAnimal.Eat();
  48: 
  49:         myAnimal = myDog; 
  50:         myAnimal.Eat();   
  51:         myAnimal = myBird;
  52:         myAnimal.Eat();   
  53:         myAnimal = myFish;
  54:         myAnimal.Eat();   
  55:     }
  56: }
The animal ate!
The dog ate!
The bird ate!
The fish ate!

همانطور که مشاهده می کنید 4 کلاس مختلف تعریف کرده ایم. Animal کلاس پایه است و سه کلاس دیگر از آن مشتق می شوند. هر کلاس متد Eat() مربوط به خود را دارد. نمونه ای از هر کلاس ایجاد کرده ایم (45-42). حال متد Eat() را به وسیله نمونه ایجاد شده از کلاس Animal به صورت زیر فراخوانی می کنیم :

Animal myAnimal = new Animal();

myAnimal.Eat();

در مرحله بعد چندریختی روی می دهد. همانطور که در مثال بالا مشاهده می کنید شی Dog را برابر نمونه ایجاد شده از کلاس Animal قرار می دهیم (خط 49) و متد Eat() را بار دیگر فراخوانی می کنیم (خط 50). حال با وجود اینکه ما از نمونه کلاس Animal استفاده کرده ایم ولی متد Eat() کلاس Dog فراخوانی می شود. این به دلیل تاثیر چند ریختی است.

سپس دو شی دیگر (Bird و Fish) را برابر نمونه ایجاد شده از کلاس Animal قرار می دهیم و متد Eat() مربوط به هر یک را فراخوانی می کنیم(خطوط 54-51). به این نکته توجه کنید که وقتی در مثال بالا اشیاء را برابر نمونه کلاس Animal قرار می دهیم ازعمل Cast استفاده نکرده ایم چون این کار (cast) وقتی که بخواهیم یک شی از کلاس مشتق (مثلا Dog) را در شیی از کلاس پایه (Animal) ذخیره کنیم لازم نیست. همچنین می توان کلاس Animal را با سازنده هر کلاس مشتق دیگر مقدار دهی اولیه کرد :

Animal myDog = new Dog();
Animal myBird = new Bird();
Animal myFish = new Fish();

myDog.Eat();
myBird.Eat();
myFish.Eat();

اجازه دهید که برنامه بالا را اصلاح کنیم تا مفهوم چند ریختی را بهتر متوجه شوید :

   1: package myfirstprogram;
   2: 
   3: class Animal
   4: {
   5:     public void Eat()
   6:     {
   7:         System.out.println("The animal ate!");
   8:     }
   9: }
  10: 
  11: class Dog extends Animal
  12: {
  13:     @Override
  14:     public void Eat()
  15:     {
  16:         System.out.println("The dog ate!");
  17:     }
  18:     
  19:     public void Run()
  20:     {
  21:         System.out.println("The dog ran!");
  22:     }
  23: }
  24: 
  25: class Bird extends Animal
  26: {
  27:     @Override
  28:     public void Eat()
  29:     {
  30:         System.out.println("The bird ate!");
  31:     }
  32:     
  33:     public void Fly()
  34:     {
  35:         System.out.println("The bird flew!");
  36:     }
  37: }
  38: 
  39: class Fish extends Animal
  40: {
  41:     @Override
  42:     public void Eat()
  43:     {
  44:         System.out.println("The fish ate!");
  45:     }
  46:     
  47:     public void Swim()
  48:     {
  49:         System.out.println("The fish swam!");
  50:     }
  51: }
  52: 
  53: public class MyFirstProgram 
  54: {
  55:     public static void main(String[] args) 
  56:     { 
  57:         Animal animal1 = new Dog();
  58:         Animal animal2 = new Bird();
  59:         Animal animal3 = new Fish();
  60: 
  61:         Dog  myDog  = (Dog)animal1;
  62:         Bird myBird = (Bird)animal2;
  63:         Fish myFish = (Fish)animal3;
  64: 
  65:         myDog.Run();
  66:         myBird.Fly();
  67:         myFish.Swim();
  68:     }
  69: }
The dog ran!
The bird flew!
The fish swam!

در بالا سه شی از کلاس Animal ایجاد و آنها را بوسیله سه سازنده از کلاسهای مشتق مقدار دهی اولیه کرده ایم (خطوط 59-57). سپس با استفاده از عمل cast اشیا ایجاد شده از کلاس Animal را در نمونه هایی از کلاس های مشتق ذخیره می کنیم (خطوط 63-61). وقتی این کار را انجام دادیم می توانیم متدهای مخصوص به هر یک از کلاسهای مشتق را فراخوانی کنیم (خطوط 67-65). یک را میانبر دیگر به وسیله کد زیر مشخص شده است ولی در این روش شما نمی توانید اشیا ایجاد شده از کلاس Animal را در نمونه هایی از کلاس های مشتق ذخیره می کنید.

((Dog)animal1).Run();
((Bird)animal2).Fly();
((Fish)animal3).Swim();

از چند ریختی می توان در رابط ها هم استفاده کرد. به کد زیر توجه کنید :

   1: package myfirstprogram;
   2: 
   3: interface IAnimal
   4: {
   5:     public void Eat();
   6: }
   7: 
   8: class Dog implements IAnimal
   9: {
  10:     @Override
  11:     public void Eat()
  12:     {
  13:         System.out.println("The dog ate!");
  14:     }
  15:     
  16: }
  17: 
  18: class Bird implements IAnimal
  19: {
  20:     @Override
  21:     public void Eat()
  22:     {
  23:         System.out.println("The bird ate!");
  24:     }
  25: }
  26: 
  27: class Fish implements IAnimal
  28: {
  29:     @Override
  30:    public void Eat()
  31:     {
  32:         System.out.println("The fish ate!");
  33:     }
  34: }
  35: 
  36: public class MyFirstProgram 
  37: {
  38:     public static void main(String[] args) 
  39:     { 
  40:         IAnimal myDog  = new Dog();
  41:         IAnimal myBird = new Bird();
  42:         IAnimal myFish = new Fish();
  43: 
  44:         myDog.Eat();
  45:         myBird.Eat();
  46:         myFish.Eat();
  47:     }
  48: }
The dog ate!
The bird ate!
The fish ate!

تسلط کامل بر چند ریختی و وراثت برای درک بهتر شی گرایی ضروری است.