* Полиморфизъм

Публикувано на 09 октомври 2009 от Филип Петров. Записано в Java.


Понятието „полиморфизъм“ идва от биологията. То описва „съществуване на морфологично различни индивиди в границите на един вид“ (wikipedia). Това например са пчелите и търтеите в пчелния кошер – те са от един вид, но имат съвсем различни функции. В обектно-ориентираното програмиране под „полиморфизъм“ се разбира същото – различни обекти (индивиди) от един и същи вид (базов клас) извършват различни дейности. Тук се разбира, че индивидите наследяват характерните черти на вида, но променят някои от неговите функционалности.

Досега се запознахме с  предефинирането на методи. При тях знаем, че можем да извикваме различни методи с едно и също име. Това се наричаше „предефиниране на метод“:

public class polyexample{
  public static void main(String[] args){
    ClassExample c = new ClassExample(5);
    int imultiplyer = 2;
    double dmultiplyer = 2.5;
    int x = c.multiply(imultiplyer);
    double d = c.multiply(dmultiplyer);
    System.out.println("x = "+x+", d = "+d);
  }
}

class ClassExample{
  public int x;
  public ClassExample(){
    x = 0;
  }
  public ClassExample(int x){
    this.x = x;
  }
  public int multiply(int x){
    return this.x*x;
  }
  public double multiply(double x){
    return (double)this.x * x;
  }
}

В литературата това се среща по-често просто като понятие „предефиниране на метод“ и много автори не го свързват въобще с понятието „полиморфизъм“. Въпреки, че тук нямаме конкретно обект от даден клас и нямаме наследяване, все пак можем да направим доста добра аналогия с понятието полиморфизъм. Ако приемем, че „методът“ е „вид“, а „извикването на метод с аргументи“ е „индивид“, то имаме типичното свойство на полиморфизма – различните индивиди действат по различен начин. Затова ще си позволим да въведем понятието „статичен полиморфизъм“ като синоним на „предефиниране на метод“. Също така можем да го приемем и за полиморфизъм в процедурното програмиране.

Динамичен полиморфизъм се получава тогава, когато предефинираме методи на базов клас в негов наследник. Казваме също, че по този начин променяме съществуващата реализация на метод с нова. Ето един пример – създаваме наследник и предефинираме метод print():

public class polyexample{
  public static void main(String[] args){
    ClassExample c = new ClassExample(5);
    c.print();
    SubClassExample c2 = new SubClassExample(5);
    c2.print();
  }
}

class ClassExample{
  public int x;
  public ClassExample(){
    x = 0;
  }
  public ClassExample(int x){
    this.x = x;
  }
  public void print(){
    System.out.println(this.x);
  }
}

class SubClassExample extends ClassExample{
  public int y;
  public SubClassExample(){
    super();
    y = 0;
  }
  public SubClassExample(int x){
    super(x);
    y = 0;
  }
  public void print(){
    System.out.println(this.x+" "+this.y);
  }
}

Динамично свързване на метод е третият, най-пълен тип полиморфизъм. Това е свойството на метод да върши различни неща в зависимост от обекта с който работи. Динамичното свързване на метод всъщност се свързва и с общото понятие „полиморфизъм“ в обектно-ориентираното програмиране. В известен смисъл то „надгражда“ динамичния полиморфизъм. Ето един класически пример:

public class polyexample{
  public static void main(String[] args){
    Animal a;
    Dog kuche = new Dog("Sharo");
    Cat kotka = new Cat("Pisana");
    a = kuche;
    a.speak();
    a = kotka;
    a.speak();
  }
}

abstract class Animal{
  public String name;
  public Animal(String name){
    this.name = name;
  }
  abstract void speak();
}

class Dog extends Animal{
  public Dog(String name){
    super(name);
  }
  public void speak(){
    System.out.println("Бау, бау!");
  }
}

class Cat extends Animal{
  public Cat(String name){
    super(name);
  }
  public void speak(){
    System.out.println("Мяу!");
  }
}

Виждате, че всеки път извиквахме метод „speak()“ чрез променливата „a“, която е от абстрактен тип „Animal“. По време на компилация не се знае точно кой метод „speak()“ ще бъде извикан – поради тази причина се казва, че имаме „динамично свързване на метод“ по време на изпълнение. Това е и пълното разбиране за понятието „полиморфизъм в обектно-ориентираното програмиране“.

Тук е мястото да вмъкнем аналогията с програмирането на C++ където имаше понятие „виртуални функции„, тоест такива, които могат да бъдат предефинирани. В Java всички методи са виртуални и могат да бъдат предефинирани. В C++ наричахме такова предефиниране като „полиморфизъм по време на изпълнение“ или както го дефинирахме тук – динамично свързване на метод.



Trackback URI | RSS за коментарите

Пусни коментар