ที่มา: InfoWorld วันนี้คุณจะได้เรียนรู้ว่าในกรณีใดที่นักพัฒนาควรใช้คลาสนามธรรม และในกรณีใดคืออินเทอร์เฟซ นอกจากนี้เรายังจะระบุความแตกต่างระหว่างองค์ประกอบเหล่านี้ของภาษา Java และวิธีการใช้ในโปรแกรม
คลาสนามธรรมและอินเทอร์เฟซนั้นค่อนข้างพบได้ทั่วไปในโค้ด Java และแม้แต่ใน Java Development Kit (JDK) เอง แต่ละองค์ประกอบเหล่านี้มีจุดประสงค์ที่แตกต่างกัน:

- อินเทอร์เฟซคือโครงสร้างในภาษา Java ที่ช่วยนำเมธอดนามธรรมและค่าคงที่แบบคงที่ไปใช้
- คลาสนามธรรมนั้นคล้ายคลึงกับคลาสปกติ ยกเว้นว่าสามารถรวมวิธีนามธรรมได้ นั่นคือ วิธีการที่ไม่มีเนื้อหา ไม่สามารถสร้างคลาสนามธรรมได้
อินเทอร์เฟซคืออะไร
โดยพื้นฐานแล้ว อินเทอร์เฟซคือสัญญา ดังนั้นจึงขึ้นอยู่กับการใช้งานเพื่อกำหนดวัตถุประสงค์ของการสร้าง อินเทอร์เฟซไม่สามารถใช้ตัวแปรอินสแตนซ์ที่ไม่แน่นอน แต่สามารถใช้ได้เฉพาะตัวแปรสุดท้ายเท่านั้นเมื่อใดควรใช้อินเทอร์เฟซ
อินเทอร์เฟซมีประโยชน์มากสำหรับการแยกโค้ดและการนำความหลากหลายไปใช้ เราเห็นสิ่งนี้ได้ใน JDK ด้วยList interface :public interface List<E> extends Collection<E> {
int size();
boolean isEmpty();
boolean add(E e);
E remove(int index);
void clear();
}
ดังที่คุณคงสังเกตเห็นแล้วว่าโค้ดนี้แม้จะสั้นแต่ก็มีคำอธิบายค่อนข้างมาก เราสามารถเห็นลายเซ็นวิธีการที่จะใช้ในการใช้วิธีการในส่วนต่อประสานโดยใช้คลาสที่เป็นรูปธรรมได้อย่างง่ายดาย อินเทอร์เฟซรายการประกอบด้วยสัญญาที่ArrayList , Vector , LinkedListและคลาสอื่นๆ สามารถนำมาใช้ได้ หากต้องการใช้ความหลากหลาย เราสามารถประกาศประเภทของตัวแปรของเราโดยใช้Listจากนั้นเลือกอินสแตนซ์ที่มีอยู่ นี่เป็นอีกตัวอย่างหนึ่ง:
List list = new ArrayList();
System.out.println(list.getClass());
List list = new LinkedList();
System.out.println(list.getClass());
ผลลัพธ์คือ:
คลาส java.util.ArrayList คลาส java.util.LinkedList
ในกรณีนี้ วิธีการนำไปใช้สำหรับArrayList , LinkedListและVectorจะแตกต่างกัน ซึ่งเป็นสถานการณ์ที่ดีเยี่ยมสำหรับการใช้อินเทอร์เฟซ หากคุณสังเกตเห็นว่ามีคลาสจำนวนมากอยู่ในคลาสพาเรนต์ซึ่งมีการดำเนินการของเมธอดเดียวกัน แต่มีพฤติกรรมต่างกัน ในสถานการณ์เช่นนี้ ขอแนะนำให้ใช้อินเทอร์เฟซ ต่อไปเรามาดูตัวเลือกต่างๆ ในการใช้อินเทอร์เฟซกัน
การเอาชนะวิธีการอินเทอร์เฟซ
ดังที่เราทราบกันดีอยู่แล้วว่าอินเทอร์เฟซเป็นสัญญาประเภทหนึ่งที่ต้องดำเนินการโดยคลาสที่เป็นรูปธรรม วิธีการอินเทอร์เฟซ นั้นเป็น นามธรรมโดยปริยายและต้องมีการใช้งานคลาสอย่างเป็นรูปธรรม นี่คือตัวอย่าง:public class OverridingDemo {
public static void main(String[] args) {
Challenger challenger = new JavaChallenger();
challenger.doChallenge();
}
}
interface Challenger {
void doChallenge();
}
class JavaChallenger implements Challenger {
@Override
public void doChallenge() {
System.out.println("Challenge done!");
}
}
บทสรุป:
ท้าทายเสร็จแล้ว!
โปรดทราบว่าวิธีการอินเทอร์เฟซนั้นเป็นนามธรรมโดยปริยาย ซึ่งหมายความว่าเราไม่จำเป็นต้องประกาศให้เป็นนามธรรมอย่างชัดเจน
ตัวแปรคงที่
กฎอีกข้อที่ต้องจำคืออินเทอร์เฟซสามารถมีได้เฉพาะตัวแปรคงที่เท่านั้น นี่คือตัวอย่าง:public class Challenger {
int number = 7;
String name = "Java Challenger";
}
ที่นี่ทั้งสองตัวแปรเป็นค่าสุดท้ายและคงที่โดยปริยาย ซึ่งหมายความว่าสิ่งเหล่านั้นคงที่ เป็นอิสระจากอินสแตนซ์ และไม่สามารถเปลี่ยนแปลงได้ ตอนนี้เราจะพยายามเปลี่ยนตัวแปรใน อินเทอร์เฟซ Challengerสมมติว่าดังนี้:
Challenger.number = 8;
Challenger.name = "Another Challenger";
ซึ่งจะทำให้เกิดข้อผิดพลาดในการรวบรวม:
ไม่สามารถกำหนดค่าให้กับตัวแปรสุดท้าย 'หมายเลข' ไม่สามารถกำหนดค่าให้กับตัวแปรสุดท้าย 'ชื่อ'
วิธีการเริ่มต้น
เมื่อมีการแนะนำวิธีการเริ่มต้นใน Java 8 นักพัฒนาบางคนคิดว่าพวกเขาจะเหมือนกับคลาสนามธรรม อย่างไรก็ตาม สิ่งนี้ไม่เป็นความจริงเนื่องจากอินเทอร์เฟซไม่สามารถมีสถานะได้ วิธีการเริ่มต้นอาจมีการใช้งาน แต่วิธีนามธรรมไม่มี วิธีการเริ่มต้นเป็นผลมาจากนวัตกรรมที่มีนิพจน์แลมบ์ดาและสตรีม แต่เราต้องใช้อย่างระมัดระวัง วิธีการใน JDK ที่ใช้วิธีการเริ่มต้นคือforEach ()ซึ่งเป็นส่วนหนึ่งของ อินเทอร์เฟซ Iterable แทนที่จะคัดลอกโค้ดลงในแต่ละIterableเราสามารถใช้forEach method ซ้ำได้ :default void forEach(Consumer<? super T> action) {
// Code implementation here...
การใช้งาน Iterable ใดๆสามารถใช้ เมธอด forEach()ได้โดยไม่ต้องมีการใช้งานเมธอดใหม่ จากนั้นเราสามารถใช้รหัสซ้ำด้วยวิธีเริ่มต้นได้ มาสร้างวิธีการเริ่มต้นของเราเองกัน:
public class DefaultMethodExample {
public static void main(String[] args) {
Challenger challenger = new JavaChallenger();
challenger.doChallenge();
}
}
class JavaChallenger implements Challenger { }
interface Challenger {
default void doChallenge() {
System.out.println("Challenger doing a challenge!");
}
}
ผลลัพธ์:
ผู้ท้าชิงทำสิ่งที่ท้าทาย!
สำหรับวิธีการเริ่มต้น สิ่งสำคัญคือต้องทราบว่าแต่ละวิธีดังกล่าวจำเป็นต้องได้รับการปฏิบัติ วิธีการเริ่มต้นไม่สามารถเป็นแบบคงที่ได้ ตอนนี้เรามาดูคลาสนามธรรมกันดีกว่า
แก่นแท้ของคลาสนามธรรม
คลาสนามธรรมสามารถมีสถานะพร้อมตัวแปรอินสแตนซ์ได้ ซึ่งหมายความว่าสามารถใช้และแก้ไขตัวแปรอินสแตนซ์ได้ นี่คือตัวอย่าง:public abstract class AbstractClassMutation {
private String name = "challenger";
public static void main(String[] args) {
AbstractClassMutation abstractClassMutation = new AbstractClassImpl();
abstractClassMutation.name = "mutated challenger";
System.out.println(abstractClassMutation.name);
}
}
class AbstractClassImpl extends AbstractClassMutation { }
บทสรุป:
ผู้ท้าชิงกลายพันธุ์
วิธีนามธรรมในคลาสนามธรรม
เช่นเดียวกับอินเทอร์เฟซ คลาสนามธรรมสามารถมีเมธอดนามธรรมได้ วิธีนามธรรมคือวิธีการที่ไม่มีเนื้อหา ต่างจากอินเทอร์เฟซ วิธีการเชิงนามธรรมในคลาสนามธรรมจะต้องได้รับการประกาศอย่างชัดเจนว่าเป็นนามธรรม นี่คือตัวอย่าง:public abstract class AbstractMethods {
abstract void doSomething();
}
และนี่คือความพยายามที่จะประกาศวิธีการโดยไม่ต้องมีการนำไปปฏิบัติและไม่มี คีย์เวิร์ดabstract :
public abstract class AbstractMethods {
void doSomethingElse();
}
ขออภัย ส่งผลให้เกิดข้อผิดพลาดในการรวบรวม:
ไม่มีเนื้อความของวิธีการหรือประกาศบทคัดย่อ
เมื่อใดควรใช้คลาสนามธรรม
แนะนำให้ใช้คลาสนามธรรมเมื่อคุณต้องการใช้สถานะที่ไม่แน่นอน ตัวอย่างเช่น Java Collections Framework มี คลาส AbstractListที่ใช้สถานะของตัวแปร ในกรณีที่คุณไม่จำเป็นต้องรักษาสถานะคลาส โดยปกติควรใช้อินเทอร์เฟซจะดีกว่าความแตกต่างระหว่างคลาสนามธรรมและอินเทอร์เฟซ
จากมุมมองของการเขียนโปรแกรมเชิงวัตถุ ข้อแตกต่างที่สำคัญระหว่างอินเทอร์เฟซและคลาสนามธรรมก็คือ อินเทอร์เฟซไม่สามารถมีสถานะได้ ในขณะที่คลาสนามธรรมสามารถมีสถานะพร้อมกับตัวแปรอินสแตนซ์ได้ ข้อแตกต่างที่สำคัญอีกประการหนึ่งคือคลาสสามารถใช้อินเทอร์เฟซได้มากกว่าหนึ่งอินเทอร์เฟซ แต่สามารถขยายคลาสนามธรรมได้เพียงคลาสเดียวเท่านั้น โซลูชันนี้ขึ้นอยู่กับข้อเท็จจริงที่ว่าการสืบทอดหลายรายการ (ขยายมากกว่าหนึ่งคลาส) สามารถนำไปสู่การหยุดชะงักของโค้ดได้ นักพัฒนาภาษา Java ตัดสินใจหลีกเลี่ยงสิ่งนี้ ข้อแตกต่างอีกประการหนึ่งคืออินเทอร์เฟซสามารถใช้งานได้โดยคลาสหรือขยายโดยอินเทอร์เฟซ แต่คลาสสามารถขยายได้เท่านั้น สิ่งสำคัญคือต้องทราบว่านิพจน์แลมบ์ดาสามารถใช้ได้กับอินเทอร์เฟซการทำงานเท่านั้น (หมายถึงอินเทอร์เฟซที่มีเพียงวิธีเดียวเท่านั้น) ในขณะที่คลาสนามธรรมที่มีวิธีนามธรรมเพียงวิธีเดียวไม่สามารถใช้นิพจน์แลมบ์ดาได้ ต่อไปนี้เป็นข้อแตกต่างเพิ่มเติมระหว่างคลาสนามธรรมและอินเทอร์เฟซ อินเตอร์เฟซ:- สามารถมีได้เฉพาะตัวแปรคงที่สุดท้ายเท่านั้น อินเทอร์เฟซไม่สามารถเปลี่ยนสถานะของตนเองได้
- คลาสสามารถใช้หลายอินเทอร์เฟซได้
- สามารถนำไปใช้งานได้โดยใช้คีย์เวิร์ด Implements อินเทอร์เฟซสามารถขยายอินเทอร์เฟซอื่นได้
- วิธีการสามารถใช้ได้เฉพาะฟิลด์สุดท้ายแบบคงที่ พารามิเตอร์ หรือตัวแปรท้องถิ่นเท่านั้น
- เฉพาะอินเทอร์เฟซที่ใช้งานได้เท่านั้นที่สามารถใช้ฟังก์ชัน lambda ใน Java ได้
- ไม่สามารถมีตัวสร้างได้
- อาจมีวิธีการเชิงนามธรรม
- สามารถมีวิธีการเริ่มต้นและแบบคงที่ (แนะนำใน Java 8)
- สามารถมีวิธีส่วนตัวพร้อมการใช้งาน (แนะนำใน Java 9)
- สามารถมีอินสแตนซ์หรือตัวแปรคงที่ใดๆ ก็ได้ เปลี่ยนแปลงหรือไม่เปลี่ยนรูปได้
- คลาสสามารถขยายคลาสนามธรรมได้เพียงคลาสเดียวเท่านั้น
- อาจมีอินสแตนซ์ของฟิลด์ พารามิเตอร์ หรือตัวแปรท้องถิ่นที่ไม่แน่นอน
- คลาสนามธรรมที่มีวิธีนามธรรมเพียงวิธีเดียวไม่สามารถใช้นิพจน์แลมบ์ดาได้
- อาจมีตัวสร้าง
- มีวิธีไหนก็ได้
GO TO FULL VERSION