สวัสดี! วันนี้เราจะพูดถึงแนวคิดที่สำคัญใน Java: อินเทอร์เฟซ คำนี้น่าจะคุ้นหูกันดี ตัวอย่างเช่น โปรแกรมคอมพิวเตอร์และเกมส่วนใหญ่มีอินเทอร์เฟซ ในความหมายกว้างๆ อินเทอร์เฟซคือ 'รีโมตคอนโทรล' ประเภทหนึ่งที่เชื่อมต่อสองฝ่ายที่มีปฏิสัมพันธ์ ตัวอย่างง่ายๆ ของอินเทอร์เฟซในชีวิตประจำวันคือรีโมทคอนโทรลของทีวี โดยจะเชื่อมต่อวัตถุสองชิ้น — คนกับทีวี — และทำงานต่างๆ กัน: เพิ่มหรือลดระดับเสียง สลับช่อง และเปิดหรือปิดทีวี ฝ่ายหนึ่ง (บุคคลนั้น) ต้องเข้าถึงอินเทอร์เฟซ (กดปุ่มบนรีโมทคอนโทรล) เพื่อให้ฝ่ายที่สองดำเนินการ ตัวอย่างเช่น เพื่อให้ทีวีเปลี่ยนเป็นช่องถัดไป ยิ่งไปกว่านั้น ผู้ใช้ไม่ ไม่จำเป็นต้องรู้ว่ามีการจัดระเบียบทีวีอย่างไรหรือกระบวนการเปลี่ยนช่องใช้งานภายในอย่างไร สิ่งเดียวที่ผู้ใช้สามารถเข้าถึงได้คืออินเทอร์เฟซ วัตถุประสงค์หลักเพื่อให้ได้ผลลัพธ์ที่ต้องการ สิ่งนี้เกี่ยวข้องกับการเขียนโปรแกรมและ Java หรือไม่ ทุกอย่าง :) การสร้างส่วนต่อประสานนั้นคล้ายกับการสร้างคลาสปกติ แต่ใช้คำแทนclassเราระบุส่วนต่อประสานคำ มาดูอินเทอร์เฟซ Java ที่ง่ายที่สุด ดูว่ามันทำงานอย่างไร และเหตุใดเราจึงต้องใช้:
คุณเคยทำงานกับ อินเทอร์เฟซ
public interface CanSwim {
public void swim();
}
เราได้สร้างอินเทอร์เฟซ CanSwim มันคล้ายกับรีโมตคอนโทรลของเรา แต่มี 'ปุ่ม' เพียงปุ่มเดียว: วิธีการว่ายน้ำ () แต่เราจะใช้งานรีโมทคอนโทรลนี้ได้อย่างไร? ในการทำเช่นนี้ เราจำเป็นต้องใช้วิธีการ เช่น ปุ่มควบคุมระยะไกลของเรา ในการใช้อินเทอร์เฟซ บางคลาสในโปรแกรมของเราต้องใช้เมธอดของมัน มาสร้างชั้นเรียนที่มีวัตถุ 'ว่ายน้ำได้' กันเถอะ ตัวอย่างเช่น คลาส Duckเหมาะกับ:
public class Duck implements CanSwim {
public void swim() {
System.out.println("Duck, swim!");
}
public static void main(String[] args) {
Duck duck = new Duck();
duck.swim();
}
}
"เราเห็นอะไรที่นี่ คลาสDuckนั้น 'เชื่อมโยง' กับอินเตอร์เฟสCanSwim โดยใช้ คีย์เวิร์ด Implementคุณอาจจำได้ว่าเราใช้กลไกที่คล้ายกันในการเชื่อมโยงสองคลาสผ่านการสืบทอด แต่ในกรณีนั้น เราใช้คำขยาย สำหรับ เราสามารถแปลคำว่า ' public class Duck Implement CanSwim ' ได้อย่างแท้จริงว่า: ' The public Duck class Impulse the CanSwim interface ' ซึ่งหมายความว่าคลาสที่เกี่ยวข้องกับอินเตอร์เฟสจะต้องใช้เมธอดทั้งหมดของมัน หมายเหตุ: Duck
คลาสของเราก็เหมือนกับ อินเตอร์เฟสCanSwim
มีswim()
เมธอด และมีลอจิก นี่เป็นข้อกำหนดบังคับ ถ้าเราแค่เขียนpublic class Duck implements CanSwim
โดยไม่ต้องสร้างswim()
เมธอดในDuck
คลาส คอมไพเลอร์จะให้ข้อผิดพลาดแก่เรา: Duck is not abstract and does not override abstract method swim() in CanSwim Why? ทำไมสิ่งนี้ถึงเกิดขึ้น? หากเราอธิบายข้อผิดพลาดโดยใช้ตัวอย่างทีวี ก็จะเหมือนกับการมอบรีโมตคอนโทรลทีวีที่มีปุ่ม 'เปลี่ยนช่อง' ให้กับใครบางคนซึ่งไม่สามารถเปลี่ยนช่องได้ คุณสามารถกดปุ่มได้มากเท่าที่คุณต้องการ แต่จะไม่ทำงาน รีโมตคอนโทรลไม่เปลี่ยนช่องด้วยตัวเอง แต่จะส่งสัญญาณไปยังทีวีเท่านั้น ซึ่งใช้กระบวนการที่ซับซ้อนในการเปลี่ยนช่อง เป็ดของเราก็เช่นกัน มันต้องรู้วิธีว่ายน้ำจึงจะเรียกว่าใช้CanSwim
อินเทอร์เฟซได้ หากไม่ทราบวิธีการCanSwim
อินเทอร์เฟซไม่เชื่อมต่อสองฝ่าย — บุคคลและโปรแกรม บุคคลนั้นจะไม่สามารถใช้swim()
วิธีการว่ายDuck
น้ำภายในโปรแกรมได้ ตอนนี้คุณเข้าใจชัดเจนมากขึ้นว่าอินเทอร์เฟซมีไว้เพื่ออะไร อินเทอร์เฟซอธิบายพฤติกรรมที่คลาสที่ใช้อินเทอร์เฟซต้องมี 'พฤติกรรม' เป็นชุดของวิธีการ หากเราต้องการสร้างผู้ส่งสารหลายๆ คน วิธีที่ง่ายที่สุดคือสร้างMessenger
อินเทอร์เฟซ ผู้ส่งสารทุกคนต้องการอะไร? ในระดับพื้นฐานจะต้องสามารถรับและส่งข้อความได้
public interface Messenger{
public void sendMessage();
public void getMessage();
}
ตอนนี้เราสามารถสร้างคลาส Messenger ของเราที่ใช้อินเทอร์เฟซที่เกี่ยวข้องได้ ตัวคอมไพเลอร์จะ 'บังคับ' ให้เรานำไปใช้ในชั้นเรียนของเรา โทรเลข:
public class Telegram implements Messenger {
public void sendMessage() {
System.out.println("Sending a Telegram message!");
}
public void getMessage() {
System.out.println("Receiving a Telegram message!");
}
}
วอทส์แอพ:
public class WhatsApp implements Messenger {
public void sendMessage() {
System.out.println("Sending a WhatsApp message!");
}
public void getMessage() {
System.out.println("Reading a WhatsApp message!");
}
}
ไวเบอร์:
public class Viber implements Messenger {
public void sendMessage() {
System.out.println("Sending a Viber message!");
}
public void getMessage() {
System.out.println("Receiving a Viber message!");
}
}
สิ่งนี้ให้ข้อดีอะไรบ้าง? สิ่งที่สำคัญที่สุดคือข้อต่อแบบหลวม ลองจินตนาการว่าเรากำลังออกแบบโปรแกรมที่จะรวบรวมข้อมูลลูกค้า ชั้นClient
เรียนต้องการฟิลด์เพื่อระบุว่าผู้ส่งสารใดที่ลูกค้าใช้อยู่ หากไม่มีอินเทอร์เฟซ สิ่งนี้จะดูแปลก:
public class Client {
private WhatsApp whatsApp;
private Telegram telegram;
private Viber viber;
}
เราสร้างฟิลด์สามฟิลด์ แต่ไคลเอ็นต์สามารถมีแมสเซนเจอร์ได้เพียงหนึ่งฟิลด์ เราแค่ไม่รู้ว่าอันไหน ดังนั้นเราจึงต้องเพิ่มทุกความเป็นไปได้ให้กับชั้นเรียนเพื่อให้สามารถสื่อสารกับลูกค้าได้ ปรากฎว่าหนึ่งหรือสองคนจะเป็นnull
โปรแกรมที่ไม่ต้องการโดยสิ้นเชิง ควรใช้อินเทอร์เฟซของเราแทน:
public class Client {
private Messenger messenger;
}
นี่คือตัวอย่างของข้อต่อหลวม! แทนที่จะระบุคลาสผู้ส่งสารเฉพาะในClient
ชั้นเรียน เราเพียงระบุว่าลูกค้ามีผู้รับสาร อันไหนจะถูกกำหนดในขณะที่โปรแกรมทำงาน แต่ทำไมเราถึงต้องการอินเทอร์เฟซสำหรับสิ่งนี้ ทำไมพวกเขาถึงถูกเพิ่มเข้าไปในภาษา? นั่นเป็นคำถามที่ดี — และเป็นคำถามที่ถูกต้อง! เราไม่สามารถบรรลุผลลัพธ์เดียวกันโดยใช้การสืบทอดแบบธรรมดาได้หรือ? ชั้นMessenger
เรียนในฐานะผู้ปกครอง และViber
, Telegram
, และWhatsApp
ในฐานะเด็ก แน่นอนว่าเป็นไปได้ แต่มีอุปสรรค์อย่างหนึ่ง ดังที่คุณทราบแล้ว Java ไม่มีการสืบทอดหลายรายการ แต่มีการสนับสนุนหลายอินเทอร์เฟซ คลาสสามารถใช้อินเทอร์เฟซได้มากเท่าที่คุณต้องการ ลองนึกภาพว่าเรามีSmartphone
ชั้นเรียนที่มีหนึ่งApp
ช่องซึ่งแสดงถึงแอพที่ติดตั้งบนสมาร์ทโฟน
public class Smartphone {
private App app;
}
แน่นอนว่าแอปและโปรแกรมส่งข้อความนั้นคล้ายกัน แต่ก็ยังมีความแตกต่างกันอยู่ อาจมี Messenger เวอร์ชันมือถือและเดสก์ท็อป แต่แอพแสดงถึงแอพมือถือโดยเฉพาะ นี่คือข้อตกลง ถ้าเราใช้การสืบทอด เราจะไม่สามารถเพิ่มวัตถุTelegram
ในSmartphone
ชั้นเรียนได้ ท้ายที่สุดTelegram
คลาสไม่สามารถสืบทอดพร้อมกันApp
และMessenger
! และเราได้ทำให้มันสืบทอดMessenger
และเพิ่มเข้าไปในClient
คลาสแล้ว แต่Telegram
ชั้นเรียนสามารถใช้ทั้งสองอินเทอร์เฟซได้อย่างง่ายดาย! ดังนั้น เราสามารถให้Client
คลาสเป็นTelegram
ออบเจกต์เป็น a Messenger
และเราสามารถให้คลาสSmartphone
เป็นออบเจกต์App
ได้ นี่คือวิธีที่คุณทำ:
public class Telegram implements Application, Messenger {
// ...methods
}
public class Client {
private Messenger messenger;
public Client() {
this.messenger = new Telegram();
}
}
public class Smartphone {
private Application application;
public Smartphone() {
this.application = new Telegram();
}
}
ตอนนี้เรากำลังใช้Telegram
ชั้นเรียนตามที่เราต้องการ ในบางแห่งจะทำหน้าที่เป็นไฟล์App
. ในที่อื่น ๆ จะทำหน้าที่เป็นMessenger
. คุณคงสังเกตเห็นแล้วว่าเมธอดของอินเทอร์เฟซนั้น 'ว่างเปล่า' เสมอ นั่นคือไม่มีการใช้งาน เหตุผลนี้ง่ายมาก: อินเทอร์เฟซอธิบายพฤติกรรม แต่ไม่ได้นำไปใช้ 'วัตถุทั้งหมดที่ใช้CanSwim
อินเทอร์เฟซต้องว่ายน้ำได้' นั่นคือทั้งหมดที่อินเทอร์เฟซบอกเรา วิธีเฉพาะที่ปลา เป็ด และม้าว่ายน้ำเป็นคำถามสำหรับFish
, Duck
, และHorse
คลาสไม่ใช่อินเทอร์เฟซ เช่นเดียวกับการเปลี่ยนช่องเป็นงานสำหรับทีวี รีโมทจะให้ปุ่มนี้แก่คุณ อย่างไรก็ตาม การเพิ่มที่น่าสนใจปรากฏใน Java 8 — วิธีการเริ่มต้น ตัวอย่างเช่น อินเทอร์เฟซของคุณมี 10 วิธี 9 รายการมีการใช้งานที่แตกต่างกันในคลาสต่างๆ แต่มีการใช้งานเหมือนกันสำหรับทุกคน ก่อนหน้านี้ ก่อน Java 8 เมธอดอินเตอร์เฟสไม่มีการนำไปใช้งานใดๆ เลย: คอมไพเลอร์แสดงข้อผิดพลาดทันที ตอนนี้คุณสามารถทำสิ่งนี้:
public interface CanSwim {
public default void swim() {
System.out.println("Swim!");
}
public void eat();
public void run();
}
ด้วยการใช้default
คำหลัก เราได้สร้างวิธีการเชื่อมต่อด้วยการใช้งานเริ่มต้น เราจำเป็นต้องจัดให้มีการใช้ งานของเราเองสำหรับอีกสองวิธี — eat()
และrun()
— ในคลาสทั้งหมดที่ใช้ CanSwim
เราไม่จำเป็นต้องทำเช่นนี้กับเมธอดswim()
: การนำไปใช้จะเหมือนกันในทุกคลาส อย่างไรก็ตาม คุณได้พบอินเทอร์เฟซในงานที่ผ่านมาแล้ว แม้ว่าคุณจะไม่ได้สังเกตก็ตาม :) นี่คือตัวอย่างที่ชัดเจน: 
List
และSet
! แม่นยำยิ่งขึ้น คุณได้ทำงานกับการใช้งานของพวกเขา — ArrayList
, LinkedList
, HashSet
, ฯลฯ แผนภาพเดียวกันแสดงให้เห็นอย่างชัดเจนว่าคลาสหนึ่งใช้อินเทอร์เฟซหลายรายการพร้อมกัน ตัวอย่างเช่นLinkedList
ใช้List
andDeque
(คิวปลายคู่) อินเตอร์เฟส คุณคุ้นเคยกับMap
อินเทอร์เฟซหรือคุ้นเคยกับHashMap
การใช้งาน อย่างไรก็ตาม ไดอะแกรมนี้แสดงคุณลักษณะ: อินเทอร์เฟซสามารถสืบทอดอินเทอร์เฟซอื่นได้ อิน เท อSortedMap
ร์เฟซสืบทอดMap
ในขณะที่Deque
สืบทอด Queue
นี่เป็นสิ่งจำเป็นหากคุณต้องการแสดงความสัมพันธ์ระหว่างอินเทอร์เฟซ โดยที่อินเทอร์เฟซหนึ่งเป็นเวอร์ชันขยายของอีกอินเทอร์เฟซหนึ่ง ลองพิจารณาตัวอย่างด้วยQueue
อินเทอร์เฟซ เรายังไม่ได้ตรวจสอบQueues
แต่มันค่อนข้างเรียบง่ายและทำงานเหมือนคิวหรือแถวทั่วไปที่ร้านค้า คุณสามารถเพิ่มรายการที่ส่วนท้ายของคิวเท่านั้น และรับได้ตั้งแต่เริ่มต้นเท่านั้น ในบางจุด นักพัฒนาต้องการคิวเวอร์ชันปรับปรุงเพื่อเพิ่มและรับรายการที่ปลายทั้งสองด้าน ดังนั้นพวกเขาจึงสร้างDeque
ส่วนต่อประสานซึ่งเป็นคิวสองด้าน มันมีวิธีการทั้งหมดของคิวธรรมดา ท้ายที่สุดมันเป็นพาเรนต์ของคิวแบบ double-end แต่ก็ยังเพิ่มวิธีการใหม่
GO TO FULL VERSION