1. แนะนำอินเทอร์เฟซ

วันนี้เป็นวันของคุณสำหรับความรู้ หัวข้อใหม่และน่าสนใจอีกอย่างคืออินเทอร์เฟซ

แนวคิดของอินเทอร์เฟซคือลูกของหลักการนามธรรมและความหลากหลาย อินเทอร์เฟซคล้ายกับคลาสนามธรรมมาก ซึ่งเมธอดทั้งหมดเป็นแบบนามธรรม มีการประกาศในลักษณะเดียวกับ class แต่เราใช้interfaceคีย์เวิร์ด

interface Feline
{
   void purr();
   void meow();
   void growl();
}

ข้อเท็จจริงที่เป็นประโยชน์เกี่ยวกับอินเทอร์เฟซมีดังนี้

1. การประกาศอินเทอร์เฟซ

interface Drawable
{
   void draw();
}

interface HasValue
{
   int getValue();
}
  1. แทนที่จะเป็นclassคีย์เวิร์ด เราเขียนinterface.
  2. มันมีวิธีการที่เป็นนามธรรมเท่านั้น (อย่าเขียนabstractคำหลัก)
  3. ในความเป็นจริงอินเทอร์เฟซมีpublicวิธีการ ทั้งหมด
2. การสืบทอดอินเทอร์เฟซ

อินเทอร์เฟซสามารถสืบทอดอินเทอร์เฟซเท่านั้น แต่อินเทอร์เฟซสามารถมีผู้ปกครองได้หลายคน อีกวิธีในการพูดคือการบอกว่า Java มีการสืบทอดอินเทอร์เฟซหลายรายการ ตัวอย่าง:

interface Piece extends Drawable, HasValue
{
   int getX();
   int getY();
}

3. การสืบทอดคลาสจากอินเตอร์เฟส

คลาสสามารถสืบทอดหลายอินเตอร์เฟส (จากคลาสเดียวเท่านั้น) สิ่งนี้ทำได้โดยใช้implementsคำหลัก ตัวอย่าง:

abstract class ChessItem implements Drawable, HasValue
{
   private int x, y, value;
   public int getValue()
   {
      return value;
   }

   public int getX()
   {
      return x;
   }

   public  int getY()
   {
      return y;
   }
}

คลาส ChessItem ถูกประกาศเป็นนามธรรม: มันนำเมธอดที่สืบทอดมาทั้งหมดมาใช้ ยกเว้นdraw. กล่าวอีกนัยหนึ่งChessItemคลาสมีหนึ่งเมธอดนามธรรมdraw()

ความหมายทางเทคนิคของ คำหลัก extendsand implementsเหมือนกัน: ทั้งคู่เป็นกรรมพันธุ์ ความแตกต่างถูกสร้างขึ้นเพื่อปรับปรุงการอ่านรหัส เรายังบอกว่าคลาสได้รับการสืบทอด (ผ่านextends) และอินเทอร์เฟซถูกนำไปใช้ (ผ่านimplements)

4. ตัวแปร

นี่คือสิ่งที่สำคัญที่สุด: ไม่สามารถประกาศตัวแปรธรรมดาในอินเทอร์เฟซได้ (แม้ว่าตัวแปรแบบสแตติกจะทำได้ก็ตาม)

แต่ทำไมเราถึงต้องการอินเทอร์เฟซ? ใช้เมื่อไหร่? อินเทอร์เฟซมีข้อดีสองประการที่เหนือกว่าคลาส:



2. แยก "คำอธิบายวิธีการ" ออกจากการนำไปใช้

ก่อนหน้านี้ เราเคยกล่าวไว้ว่าหากคุณต้องการอนุญาตให้เมธอดของคลาสของคุณถูกเรียกจากคลาสอื่น วิธีการของคุณจะต้องถูกทำเครื่องหมายด้วยpublicคีย์เวิร์ด หากคุณต้องการให้เมธอดบางส่วนถูกเรียกจากในคลาสของคุณเท่านั้น คุณต้องทำเครื่องหมายด้วยprivateคีย์เวิร์ด กล่าวอีกนัยหนึ่ง เราแบ่งวิธีการของชั้นเรียนออกเป็นสองประเภท: "สำหรับทุกคนใช้" และ "สำหรับใช้เองเท่านั้น"

อินเทอร์เฟซช่วยเสริมความแข็งแกร่งของแผนกนี้ให้แข็งแกร่งยิ่งขึ้น เราจะสร้าง "คลาสพิเศษสำหรับทุกคนที่ใช้" รวมถึงคลาสที่สอง "สำหรับใช้เองเท่านั้น" ซึ่งจะสืบทอดคลาสแรก นี่คือลักษณะคร่าวๆ:

ก่อน หลังจาก
class Student
{
   private String name;
   public Student(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
interface Student
{
   public String getName();
}

class StudentImpl implements Student
{
   private String name;
   public StudentImpl(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
}
public static void main(String[] args)
{
   Student student = new Student("Alibaba");
   System.out.println(student.getName());
}
public static void main(String[] args)
{
   Student student = new StudentImpl("Ali")
   System.out.println(student.getName());
}

เราแบ่งคลาสของเราออกเป็นสอง: อินเทอร์เฟซและคลาสที่สืบทอดอินเทอร์เฟซ และข้อดีที่นี่คืออะไร?

คลาสที่แตกต่างกันจำนวนมากสามารถใช้ (สืบทอด) อินเทอร์เฟซเดียวกันได้ และแต่ละคนสามารถมีพฤติกรรมของตนเองได้ ตัวอย่างเช่น มีการใช้งาน อินเทอร์เฟซArrayList LinkedListที่แตกต่างกันสองแบบList

ดังนั้นเราจึงซ่อนไม่เพียง แต่การใช้งานที่หลากหลาย แต่ยังรวมถึงคลาสการใช้งานด้วย (เนื่องจากเราต้องการส่วนต่อประสานในรหัสเท่านั้น) สิ่งนี้ทำให้เรามีความยืดหยุ่นมาก: ทันทีที่โปรแกรมทำงาน เราสามารถแทนที่วัตถุหนึ่งด้วยอีกวัตถุหนึ่ง เปลี่ยนพฤติกรรมของวัตถุโดยไม่ส่งผลกระทบต่อคลาสทั้งหมดที่ใช้งาน

นี่เป็นเทคนิคที่ทรงพลังมากเมื่อรวมกับความหลากหลาย สำหรับตอนนี้ มันยังห่างไกลจากความชัดเจนว่าเหตุใดคุณจึงควรทำเช่นนี้ ก่อนอื่นคุณต้องพบกับโปรแกรมที่มีคลาสหลายสิบหรือหลายร้อยคลาสเพื่อที่จะเข้าใจว่าอินเทอร์เฟซสามารถทำให้ชีวิตของคุณง่ายขึ้นกว่าที่ไม่มีพวกมัน


3. มรดกหลายรายการ

ใน Java คลาสทั้งหมดสามารถมีคลาสพาเรนต์ได้เพียงหนึ่งคลาสเท่านั้น ในภาษาโปรแกรมอื่นๆ คลาสมักจะมีพาเรนต์หลายคลาส สะดวกมาก แต่ก็ทำให้เกิดปัญหามากมาย

ผู้สร้างของ Java มาถึงจุดประนีประนอม: พวกเขาห้ามการสืบทอดหลายคลาส แต่อนุญาตให้มีการสืบทอดอินเทอร์เฟซหลายรายการ อินเทอร์เฟซสามารถมีหลายอินเทอร์เฟซหลัก คลาสสามารถมีอินเทอร์เฟซพาเรนต์ได้หลายตัว แต่คลาสพาเรนต์เดียวเท่านั้น

เหตุใดพวกเขาจึงห้ามการสืบทอดหลายคลาส แต่อนุญาตให้มีการสืบทอดอินเทอร์เฟซหลายรายการ เพราะปัญหามรดกที่เรียกว่าเพชร:

มรดกหลายรายการ

เมื่อคลาส B สืบทอดคลาส A ก็จะไม่รู้อะไรเลยเกี่ยวกับคลาส C และ D ดังนั้นจึงใช้ตัวแปรของคลาส A ตามที่เห็นสมควร คลาส C ทำเช่นเดียวกัน: ใช้ตัวแปรของคลาส A แต่ด้วยวิธีที่แตกต่างกัน และทั้งหมดนี้ส่งผลให้เกิดความขัดแย้งในคลาส D

ลองดูตัวอย่างง่ายๆ ต่อไปนี้ สมมติว่าเรามี 3 คลาส:

class Data
{
   protected int value;
}
class XCoordinate extends Data
{
   public void setX (int x) { value = x;}
   public int getX () { return value;}
}
class YCoordinate extends Data
{
   public void setY (int y) { value = y;}
   public int getY () { return value; }
}

ชั้นข้อมูลเก็บvalueตัวแปร คลาสที่สืบทอดมาของ XCoordinate ใช้ตัวแปรนั้นเพื่อเก็บxค่า และYCoordinateคลาสที่สืบทอดมาจะใช้ตัวแปรนั้นเพื่อเก็บyค่า

และมันใช้งานได้ แยกกัน แต่ถ้าเราต้องการให้คลาส XYCoordinates สืบทอดทั้งคลาสXCoordinateและYCoordinateคลาส เราจะได้รับรหัสที่เสียหาย คลาสนี้จะมีเมธอดของคลาสบรรพบุรุษ แต่จะใช้งานไม่ถูกต้องเพราะมีเหมือนกันvalue variable.

แต่เนื่องจากอินเทอร์เฟซไม่สามารถมีตัวแปรได้ จึงไม่มีความขัดแย้งแบบนี้ ดังนั้น จึงอนุญาตให้มีการสืบทอดอินเทอร์เฟซหลายรายการได้