Java: ინტერფეისები

interface(ინტერფეისი) ჯავას ერთერთი ყველაზე მნიშვნელოვანი დეტალია. თავად სიტყვა ინტერფეისი საუკეთესოდ აღწერს მის დანიშნულებას, თუმცა უფრო კონკრეტულ მაგალითად შეგვიძლია განვიხილოთ თავად კლასი და კალსის ობიექტი.

რამდენადაც ვიცით ურთიერთქმედება კლასებთან და კლასის ობიექტებთან ხდება მათში განსაზღვრული მეთოდების მეშვეობით, ამ შემთხვევაში შეგვიძლია ვთქვათ რომ ის მეთოდები რომლის მეშვეობითაც ვმუშაობთ ობიექტთან არის ამ ობიექტის ინტერფეისი.

მაგალითად თუ გვაქვს კლასი:

1
2
3
4
5
6
public class MyClass {
   public void doSomething() {
        String myString = "doing";
        System.out.println(myString + " something");
   }
}

ხოლო შემდეგ ამ კლასს თუ გამოვიყენებთ სხვა ნებისმიერ კლასში:

1
2
3
4
5
6
public class SomeOtherClass {
   public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.doSomething();
   }
}

შედეგად მივიღებთ “doing something” სტრიქონს:

doing something

ამ შემთხვევაში უბრალოდ გამოყენებულ იქნა MyClass კლასის doSomething() მეთოდი, სწორედ ამ მეთოდზე შეგვიძლია ვთქვათ რომ ეს არის კლასის ინტერფეისი, რადგან მისი მეშვეობით ვმუშაობთ კლასთან. ასევე საგულისხმოა ის დეტალი რომ კლიენტისათვის(ამ შემთხვევაში SomeOtherClass – ის main მეთოდი) აბსოლუტურად უმნიშვნელოა doSomething() მეთოდის რეალიზაციის დეტალები, ასეთ შემთხვევაში საკმარისია მხოლოდ იმის ცოდნა რომ doSomething მეთოდი არსებობს და მასზე წვდომა გაგვაჩნია.

თუმცა პროგრამირებაში ხშირად არის ისეთი მომენტები როდესაც საჭიროა ინტერფეისის წინასწარ აღწერა. როდესაც ავღწერთ ინტერფეისს, რეალურად ხდება განსაზღვრა იმისა თუ რა შეუძლია კლასს, მაგრამ ამ შემთხვევაში არ განისაზღვრება ის თუ როგორ მოხდება ამ შესაძლებლობის რეალიზაცია. ინტერფეისი არის ერთგვარი კონტრაქტი კლასისათვის.

მაგალითად თუ ავღწერთ ინტერფეისს სახელად Movable (მოძრავი), და მასში განვსაზღვრავთ მეთოდებს move(), moveUp(), moveDown(), ნებისმიერი კლასი რომელიც მოახდენს ამ ინტეფეისის რეალიზაციას ვალდებული იქნება ჩამოთვლილი მეთოდების რეალიზაციაზე – ეს ნიშნავს რომ კლასი ეთანხმება კონტრაქტს.

იმ შემთხვევაში თუ გვინდა რომ რომელიმე კლასი გახდეს Movable, ამისათვის საკმარისია Movable ინტერფეისის რეალიზაცია(იმპლემენტაცია), რაც გამოიხატება იმაში რომ კლასში უნდა მოხდეს Movable ინტერფეისში აღწერილი move(), moveUp(), moveDown() მეთოდების რეალიზაცია.

თავად ინტერფეისი აღიწერება შემდეგნაირად:

1
2
3
4
5
interface Movable {
     public void move();
     public void moveUp();
     public void moveDown();
}

მაგალითიდან ნათლად ჩანს რომ ინტერფეისში განვსაზღვრეთ მხოლოდ მეთოდები ტანის გარეშე. ანუ ავღწერეთ ის თუ რა არის შესაძლებელი, მაგრამ მეთოდების რეალიზაცია(ანუ როგორ ) ცალსახად უნდა მოხდეს კლასში, მაგალითად:

1
2
3
4
5
6
7
8
9
10
11
class MyMovableClass implements Movable {
     public void move() {
          System.out.println("just moving");
     }
     public void moveUp() {
          System.out.println("now moving UP");
     }
     public void moveDown() {
          System.out.println("and now moving DOWN");
     }
}

MyMovableClass კლასი ახორციელებს Movable ინტერფეისის რეალიზაციას. ამის მითითება ხდება implemenets გასაღები სიტყვის გამოყენებით. საგულისხმოა ის ფაქტი რომ განსხვავებით მემკვიდრეობისაგან სადაც extends ის შემდეგ შეგვიძლია მივუთითოთ მხოლოდ ერთი კლასი, implemenets – ის შემთხვევაში შეგვიძლია ჩამოვთვალოთ რამდენიმე ინტერფეისი. მაგალითად:

1
2
3
calss SomeClass implements Movable, OtherInterface, OneMoreInterface {
     //rest of code here
}

როდესაც საჭიროა ინტერფეისის რეალიზაცია, ეს ნიშნავს იმას რომ ვეთანხმებით ინტერფეისის მიერ განსაზღვრულ კონტრაქტს. რითიც ვალდებულებას ვიღებთ ინტერფეისში განსაზღვრული ყველა მეთოდის რეალიზაციაზე, და ნებისმიერი ვისთვისაც კი ცნობილია თუ რას აკეთებს ინტერფეისი(იცის თუ რა მეთოდებია განსაზღვრული, მაგრამ ამავდროულად აბსოლუტურად უმნიშვნელოა თუ როგორ არის მეთოდები რეალიზებული), მარტივად შეუძლია გამოიძახოს კონკრეტული რეალიზაციის კლასის ობიექტის მეთოდები – გამოიყენოს კლასის ინტერფეისი.

კონკრეტული რეალიზაციის კლასი, ეს არის კლასი რომელიც იღებს ვალდებულებას(ეთანხმება კონტრაქტს) რომ მასში მოხდება ინტერფეისის ყველა მეთოდის რელიზაცია. იმისათვის რომ კლასს ვუწოდოთ რეალიზაციის კლასი, იგი უნდა აკმაყოფილებდეს შემდეგ პირობებს:

  • იგი არ უნდა იყოს abstract;
  • მასში უნდა იყოს რეალიზებული ინტერფეისში/ინტერფეისებში განსაზღვრული ყველა მეთოდი;

რა უნდა გვახსოვდეს ინტერფეისების შესახებ?

პირველ რიგში ინტერფეისი შეგვიძლია განვიხილოთ როგორც ნამდვილი აბსტრაქტული კლასი. აბსტრაქტული კლასის აბსტრაქტული მეთოდების მსგავსად, ინტერფეისში აღიწერება მეთოდები რეალიზაციის გარეშე, თუმცა აბსტრაქტული კლასისაგან განსხვავებით მასში შეუძლებელია ჩვეულებრივი მეთოდების აღწერა. ინტერფეისისათვის დამახასიათებელი წესები და შეზღუდვები მოყვანილია ქვემოთ:

  • ინტერფეისი არაცხადად არის abstract აბსტრაქტული და მისი აღწერისას არ არის საჭირო abstract – ის მითითება;
  • ინტერფეისის ყველა მეთოდი არაცხადად არის public და abstract. რაც ნიშნავს იმას რომ არ არის საჭირო ამ მოდიფიკატორების მითითება მეთოდების აღწერისას, რადგან ისინი მაინც ყოველთვის არიან public და abstract;
  • მეთოდების აღწერისას დაუშვებელია private და protected წვდომის მოდიფიკატორების გამოყენება, რადგან ყველა მეთოდი აუცილებლად უნდა იყოს public;
  • ინტერფეისში აღწერილი ნებისმიერი ცვლადი უნდა იყოს public, static და final. რაც ნიშნავს იმას რომ ინტერფეისში შესაძლებელია მხოლოდ კონსტანტების აღწერა;
  • შეუძლებელია static(სტატიკური) მეთოდების აღწერა;
  • რადგან ინტერფეისის ყველა მეთოდი არის abstract(აბსტრაქტული), შეუძლებელია მათი აღწერა როგორც final;
  • შესაძლებელია რომ ინტერფეისი იყოს, სხვა ინტერფეისების მემკვიდრე(extends – ის შემდეგ შესაძლებელია ერთი ან მეტი ინტერფეისის მითითება);
  • შეუძლებელია რომ ინტერფეისი იყოს მემკვიდრე ჩვეულებრივი ან აბსტრაქტული კლასისა;
  • ინტერფეისის მეშვეობით შეუძლებელია სხვა ინტერფეისის(ინტერფეისების) რეალიზაცია. ანუ ჩაწერა interface MyInterface implements AnotherInterface {} დაუშვებელი და შეუძლებელია;
  • ინტერფეისი უნდა აღიწეროს interface გასაღები სიტყვის მეშვეობით;


ინტერფეისის აღწერის მაგალითები

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//ინტერფეისი ნაგულისხმევი წვდომის მოდიფიკატორით
interface Movable {
  //rest of code here
}

//ინტერფეისი public წვდომის მოდიფიკატორით
public interface Movable {
  //rest of code here
}

//ინტერფეისი abstract მოდიფიკატორით
//ინტერფეისი public წვდომის მოდიფიკატორით
public abstract interface Movable {
  //rest of code here
}

ინტერფეისი აღწერა დასაშვებია ზემოთ ჩამოთვლილი ნებისმიერი სახით. თუმცა უნდა გვახსოვდეს რომ, ინტერფეისის არწერისას abstract მოდიფიკატორის მითითება აბსოლუტურად ზედმეტია რადგან ინტერფეისი არაცხადად და აუცილებლად არის abstract. public წვდომის მოდიფიკატორის მითითება კი უნდა მოხდეს საჭიროებისა და აუცილებლობის მიხედვით.


ინტერფეისის მეთოდების აღწერის მაგალითები

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//ინტერფეისი მეთოდების ნაგულისხმევი მოდიფიკატორებით (public abstract)
interface Movable {
  void move();
  void moveUp();
  void moveDown();
}

//ინტერფეისი public მეთოდების აღწერით
interface Movable {
  public void move();
  public void moveUp();
  public void moveDown();
}

//ინტერფეისი public abstract მეთოდების აღწერით
interface Movable {
  public abstract void move();
  public abstract void moveUp();
  public abstract void moveDown();
}

//ინტერფეისი abstract public მეთოდების აღწერით
interface Movable {
  abstract public void move();
  abstract public void moveUp();
  abstract public void moveDown();
}

მაგალითში ნაჩვენებია ერთი და იგივე ინტერფეისის აღწერის სხვადასხვა ხერხები, ყველა ნაჩვენები აღწერა სწორია და დასაშვები, მიუხედავად განსხვავებული აღწერისა ყველა ინტერფეისი არის აბსოლუტურად იდენტური. თუმცა მიუხედავად იმისა რომ მოყვანილ მაგალითებში გამოვიყენეთ public და abstract მოდიფიკატორები, მათი გამოყენება აბსოლუტურად არასაჭიროა რადგან ინტერფეისის ყველა მეთოდი ნაგულისხმევად არის public და abstract.

ინტერფეისებთან მუშაობის დროს ასევე მნიშვნელოვანია გვახსოვდეს რომ ინტერფეისი შესაძლებელია იყოს სხვა ინტერფეისისა ან ინტერფეისების მემკვიდრე. მაგალითად შესაძლებელია Movable ინტერფეისის მსგავსი მოდიფიკაცია:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//UpMovable ინტერფეისი
interface UpMovable {
  void moveUp();
}

//DownMovable ინტერფეისი
interface DownMovable {
  void moveDown();
}

//Movable ინტერფეისი, რომელიც არის UpMovable და DownMovable ინტერფეისების მემკვიდრე
interface Movable extends UpMovable, DownMovable { 
  void move();
}

მაგალითში ნაჩვენებია აღნიშნული მემკვიდრეობის შესაძლებლობის რეალიზაცია, სადაც Movable ინტერფეისის აღწერისას extends გასაღები სისტყვის შემდეგ მითითებულია ორი ახალი UpMovable და DownMovable ინტერფეისების ჩამონათვალი. ასეთ შემთხვევაში ნებისმიერ კლასი რომელიც შეეცდება Movable ინტერფეისის რეალიზაციას უკვე ვალდებული იქნება მოახდინოს არა მხოლოდ move() მეთოდის რეალიზაცია(რომელიც აღწერილია Movable ინტერფეისში), არამედ იგი ვალდებული იქნება ასევე მოახდინოს moveUp() და moveDown() მეთოდების რეალიზაცია რომლებიც განსაზღვურლია შესაბამის ინტერფეისებში. რეალიზაციის მაგალითი:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class InterfaceTest implements Movable {
 
  //implement moveUp() method
  public void moveUp() {
    //rest of code here
  }
 
  //implement moveDown() method
  public void moveDown() {
    //rest of code here
  }
 
  //implement move() method
  public void move() {
    //rest of code here
  }
 
}

ამ შემთხვევაში InterfaceTest კლასში რეალიზებული ყველა ინტერფეისის მეთოდი. რადგან კალსის აღწერისას მითითებულია რომ ეს კლასი რეალიზაციას უკეთებს Movable ინტერფეიის, ხოლო თავად ეს ინტერფეისი არის მემკვიდრე UpMovable და DownMovable ინტერფეისებისა, ეს კლასი ვალდებულია რომ მასში მოხდეს ყველა ინტერფეისის მეთოდის რეალიზაცია, წინააღმდეგ შემთხვევაში კლასი არ დაკომპილირდება.


ასევე მნიშვნელოვანი და აუცილებელია, რომ კლასში მეთოდების რეალიზაციისას აუცილებლად უნდა მიეთითოს public წვდომის მოდიფიკატორი, რადგან ინტერფეისი ყველა მეთოდი არაცხადად(და აუცილებლად) არის public.


კონსტანტური ცვლადების აღწერა ინტერფეისში

როგორც ზემოთ აღინიშნა ინტერფეისში დასაშვებია მხოლოდ კონსტანტური ცვლადების აღწერა, რაც ნიშნავს იმას რომ ყველა აღწერილი ცვლადი უნდა იყოს აუცილებლად public, static და final. მაგრამ რამდენადაც ლაპარაკი გვაქვს ინტერფეისში ცვლადების აღწერაზე ეს ნიშნავს იმას რომ არ არის აუცილებელ ცვლადს მივუთითოთ public, static და final მოდიფიკატორები მისი აღწერის დროს. გამომდინარე აქედან შეგვიძლია დავწერთო შემდეგი მაგალითი:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface Movable {
       
        //კონსტანტის აღწერა ყველა მოდიფიკატორის მითითებით
  public static final int NUMBER_ONE = 1;

        //კონსტანტის აღწერა public მოდიფიკატორის გარეშე
  static final int NUMBER_TWO = 2;

        //კონსტანტის აღწერა public მოდიფიკატორის გარეშე
  public final int NUMBER_THREE = 3;

        //კონსტანტის აღწერა final მოდიფიკატორის გარეშე
  public static int NUMBER_FOUR = 4;

        //კონსტანტის აღწერა public და final მოდიფიკატორების გარეშე
  static int NUMBER_FIVE = 5;

        //კონსტანტის აღწერა public და static მოდიფიკატორების გარეშე
  final int NUMBER_SIX = 6;

        //კონსტანტის აღწერა public, static და final მოდიფიკატორების გარეშე
  int NUMBER_SEVEN = 7;
}

მოყვანილ მაგალითში ინტერფეისში აღწერილია შვიდი კონსტანტა სხვადასხვა მოდიფიკატორების მითითებით. მიუხედავად იმისა რომელ მოდიფიკატორს მივუთითებთ ან გამოვტოვებთ ნებისმიერ შემთხვევაში ყველა კონსტანტა მაინც იქნება public static და final.

ტეგები:

დატოვე კომენტარი:

ქართული კლავიატურა, ჩართვა/გამორთვა კლავიშით "~"