C, PHP, VB, .NET

Дневникът на Филип Петров


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

Публикувано на 09 октомври 2009 в раздел ПИК3 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++ наричахме такова предефиниране като „полиморфизъм по време на изпълнение“ или както го дефинирахме тук – динамично свързване на метод.

 



Добави коментар

Адресът на електронната поща няма да се публикува


*