C, PHP, VB, .NET

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


* Абстрактни класове и интерфейси

Публикувано на 09 октомври 2009 в раздел ПИК3 Java.

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

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

Нека дадем един класически пример за абстрактен клас. Ще създадем клас „геометрична фигура“, в която ще има абстрактен метод, наречен „лице“:

abstract class Figure{
  double dim1;
  double dim2;
  public Figure(double dim1, double dim2){
    this.dim1 = dim1;
    this.dim2 = dim2;
  }
  abstract double getArea();
}

Ние не можем да кажем колко ще бъде лицето на фигурата и колко ще бъде нейния периметър, защото все още не знаем точно каква ще е тя – правоъгълник или успоредник при който dim1 и dim2 са страните, триъгълник при който dim1 е основа, а dim2 е височина към нея и т.н. Когато наследим клас Figure обаче можем да дадем имплементация на този метод:

class Rectangle extends Figure{
  public Rectangle(double a, double b) {
    super(a,b);
  }
  public double getArea(){
    return this.dim1 * this.dim2;
  }
}

class Triangle extends Figure{
  public Triangle(double a, double b) {
    super(a,b);
  }
  public double getArea(){
    return (this.dim1 * this.dim2)/2;
  }
}

Още по-голямо ниво на абстракция е понятието „интерфейс“. Интерфейсът съдържа само и единствено абстрактни методи и евентуално константи (за константи ще говорим по-късно). Чрез интерфейсите ние даваме само и единствено обща насоченост как трябва да изглежда даден клас, който го „имплементира“. Нека преработим горния пример да работи по същия начин, но чрез интерфейс:

interface Figure{
  public double getArea();
}

class Rectangle implements Figure{
  double dim1;
  double dim2;
  public Rectangle(double a, double b) {
    this.dim1 = a;
    this.dim2 = b;
  }
  public double getArea(){
    return this.dim1 * this.dim2;
  }
}

class Triangle implements Figure{
  double dim1;
  double dim2;
  public Triangle(double a, double b) {
    this.dim1 = a;
    this.dim2 = b;
  }
  public double getArea(){
    return (this.dim1 * this.dim2)/2;
  }
}

Границата на това кога да използваме абстрактен клас и кога интерфейс зависи от логиката на приложението. Ако решим да включим нова геометрична фигура „окръжност“, то може би интерфейсът ще бъде по-подходящ – за лицето на окръжност не ни трябват две размерности, а ни трябва само един радиус (тоест наследяването на показания абстрактен клас „Figure“ би било нелогично, защото той съдържа две полета). Когато обаче искаме да създадем шаблон на фигура, която е задължително с две размерности, то шаблона на абстрактния клас би бил по-подходящ. С други думи отговорът на въпроса „интерфейс или абстрактен клас да използвам“ е „зависи доколко абстрактно е понятието, което ще реализираме“. По принцип ще спазваме правилото „конкретизираме и даваме колкото се може повече насоки“. Понякога ще е удачно да спазваме пълната йерархия – интерфейс, после абстрактен клас, който го имплементира, след това клас, който наследява абстрактния. Ще си позволим да въведем следните по-общи дефиниции, които също могат да служат за отправна точка:

Интерфейс: съвкупност от декларации на действия, които даден тип обекти трябва да може да извършва.

Абстрактен клас: изнесена като родителски клас базова функционалност за даден тип обекти.

 



2 коментара


  1. Константин каза:

    class Rectangle implements Figure{
    double dim1;
    double dim2;
    public Rectangle(double a, double b) {
    this.dim1 = dim1;
    this.dim2 = dim2;
    }
    public double getArea(){
    return this.dim1 * this.dim2;
    }
    }
    Тук защо е this.dim1 = dim1;
    this.dim2 = dim2;

    вместо this.dim1 = a;
    this.dim2 = b;

    ?

  2. Грешката е очевидна – ще поправя кода.

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

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


*