การเลือกกลยุทธ์การซ้อนคลาสที่เหมาะสม
ตัดสินใจเลือกรูปแบบคลาสซ้อนโดยพิจารณาจากการเชื่อมโยง ความต้องการด้านการเข้าถึง และความอ่านง่าย
การเลือกกลยุทธ์การซ้อนคลาสที่เหมาะสม เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
การเลือกกลยุทธ์การซ้อนที่เหมาะสม
Java มีทางเลือกในการซ้อนสี่แบบ ได้แก่ ระดับบนสุด คลาสซ้อนแบบสแตติก คลาสภายใน (ไม่ใช่สแตติก) และคลาสภายในเมธอดหรือนิรนาม การเลือกแบบที่เหมาะสมขึ้นอยู่กับระดับการเชื่อมโยง ความต้องการเข้าถึง และขอบเขตการนำกลับมาใช้
แผนผังการตัดสินใจ
ถามคำถามต่อไปนี้เพื่อเลือก:
- คลาสนี้ใช้เฉพาะภายในคลาสภายนอกหรือไม่ → พิจารณาการซ้อนคลาส
- คลาสนี้ต้องใช้อินสแตนซ์ภายนอกหรือไม่ → ใช้คลาสภายใน มิฉะนั้น → ใช้คลาสซ้อนแบบสแตติก
- คลาสนี้ใช้เฉพาะในเมธอดเดียวหรือไม่ → ใช้คลาสภายในเมธอดหรือคลาสนิรนาม
- คลาสนี้นำเมธอดเดียวไปใช้หรือไม่ → ใช้แลมบ์ดา
คลาสระดับบนสุด
ใช้คลาสระดับบนสุดเมื่อประเภทนั้นถูกใช้งานอย่างกว้างขวางในฐานโค้ด แสดงแนวคิดสำคัญของโดเมน หรือจะถูกนำเข้าโดยคลาสอื่นจำนวนมาก
// Top-level: used across many packages
public class Product {
// ...
}
public interface Repository<T, ID> {
Optional<T> findById(ID id);
void save(T entity);
}
// These belong in separate .java files and are widely importedคลาสซ้อนแบบสแตติก
ใช้คลาสซ้อนแบบสแตติกเมื่อคลาสนั้นมีความหมายเฉพาะในบริบทของคลาสภายนอก ไม่จำเป็นต้องใช้อินสแตนซ์ภายนอก และควรเปิดให้เข้าถึงจากภายนอกได้
class Graph {
// Edge only makes sense in the context of a Graph
public static class Edge {
public final int from, to, weight;
public Edge(int from, int to, int weight) {
this.from = from; this.to = to; this.weight = weight;
}
}
private List<Edge> edges = new ArrayList<>();
public void addEdge(int from, int to, int weight) {
edges.add(new Edge(from, to, weight));
}
}คลาสภายใน (ไม่ใช่สแตติก)
ใช้คลาสภายในเมื่อคลาสนั้นมีความเกี่ยวข้องเชิงแนวคิดอย่างมากกับอินสแตนซ์ภายนอก และต้องเข้าถึงสมาชิกส่วนตัวของคลาสนั้น เช่น ตัววนซ้ำหรืออ็อบเจ็กต์ช่วยเหลือที่เชื่อมโยงกันอย่างใกล้ชิด
class DataStore<T> {
private final List<T> data;
DataStore(List<T> data) { this.data = data; }
// Must access data — inner class makes sense
class Snapshot {
private final List<T> copy;
Snapshot() { this.copy = List.copyOf(data); } // accesses outer
T get(int idx) { return copy.get(idx); }
int size() { return copy.size(); }
}
Snapshot snapshot() { return new Snapshot(); }
}คลาสภายในเมธอด
ใช้คลาสภายในเมธอดเมื่อคลาสนั้นจำเป็นเฉพาะในเมธอดเดียว ซับซ้อนพอที่จะมีหลายเมธอดหรือมีสถานะ และต้องการจำกัดขอบเขตให้แคบที่สุด
static int countWords(String text, boolean caseSensitive) {
class WordCounter {
Map<String, Integer> counts = new HashMap<>();
void count(String word) {
String key = caseSensitive ? word : word.toLowerCase();
counts.merge(key, 1, Integer::sum);
}
int uniqueCount() { return counts.size(); }
}
WordCounter wc = new WordCounter();
for (String w : text.split("\\s+")) wc.count(w);
return wc.uniqueCount();
}
System.out.println(countWords("the cat sat on the mat", false)); // 5คลาสนิรนามกับแลมบ์ดา
ใช้คลาสนิรนามเมื่อต้องการหลายเมธอดหรือการสืบทอดจากคลาสนามธรรม ใช้แลมบ์ดากับอินเทอร์เฟซแบบ SAM
// Lambda: clean for SAM
list.sort((a, b) -> a.compareTo(b));
// Anonymous: multi-method, or extending abstract class
java.util.TimerTask task = new java.util.TimerTask() {
@Override public void run() { System.out.println("Tick!"); }
};
// TimerTask is abstract class — can't use lambda directlyตารางสรุป
ข้อมูลอ้างอิงอย่างรวดเร็ว:
- ระดับบนสุด: นำกลับมาใช้ได้อย่างกว้างขวาง เป็นประเภทของส่วนติดต่อโปรแกรมสาธารณะ
- ซ้อนแบบสแตติก: จัดกลุ่มตามตรรกะ และไม่จำเป็นต้องใช้อินสแตนซ์ภายนอก
- ภายใน: เชื่อมโยงอย่างมากกับอินสแตนซ์ภายนอก และต้องเข้าถึงสมาชิกส่วนตัว
- ภายในเมธอด: จำกัดขอบเขตอยู่ในเมธอด และซับซ้อนพอสำหรับการเป็นคลาส
- นิรนาม: การนำไปใช้ครั้งเดียวและมีอายุสั้น
- แลมบ์ดา: ใช้กับอินเทอร์เฟซแบบ SAM ไม่มีสถานะ และกระชับ
เชิงปฏิบัติ: การออกแบบ HttpClient
การประยุกต์ใช้กลยุทธ์การซ้อนกับการออกแบบ HttpClient ที่สมจริง
class HttpClient {
// Static nested: request config has no outer reference
public static class RequestConfig {
public final int timeoutMs;
public final String userAgent;
RequestConfig(int timeout, String ua) { this.timeoutMs = timeout; this.userAgent = ua; }
}
// Static nested: response is standalone data carrier
public static class Response {
public final int statusCode;
public final String body;
Response(int code, String body) { this.statusCode = code; this.body = body; }
}
private final RequestConfig config;
HttpClient(RequestConfig config) { this.config = config; }
public Response get(String url) {
// Implementation using this.config
return new Response(200, "body");
}
}หลีกเลี่ยงการซ้อนหลายชั้นเกินไป
หลีกเลี่ยงการซ้อนที่ลึกเกินหนึ่งระดับ คลาสที่ซ้อนกันลึกจะนำทางและทดสอบได้ยาก หากซับซ้อนขึ้น ควรแยกเป็นคลาสระดับบนสุดหรือคลาสที่จำกัดการเข้าถึงไว้ภายในแพ็กเกจ
ทางเลือกแบบจำกัดการเข้าถึงภายในแพ็กเกจ
แทนที่จะซ้อนคลาส ลองกำหนดให้คลาสจำกัดการเข้าถึงอยู่ภายในแพ็กเกจ โดยไม่ใช้ตัวปรับแต่งการเข้าถึง คลาสนี้จะมองเห็นได้เฉพาะภายในแพ็กเกจ แต่ทดสอบและดูแลรักษาได้ง่ายกว่าคลาสซ้อน
// In package com.example.order:
// Package-private: visible in package, no nesting
class OrderLine { // no 'public' modifier
final String sku;
final int qty;
OrderLine(String sku, int qty) { this.sku = sku; this.qty = qty; }
}
// Public class in same package can use OrderLine freely
public class Order {
private List<OrderLine> lines = new ArrayList<>();
// ...
}เรคคอร์ดและการปิดผนึกเป็นทางเลือก
คุณสมบัติสมัยใหม่ของ Java ได้แก่ เรคคอร์ดและอินเทอร์เฟซแบบปิดผนึก มักช่วยลดความจำเป็นในการใช้รูปแบบการซ้อนที่ซับซ้อนได้
// Instead of nested inner class hierarchy:
sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double r) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
record Triangle(double b, double h) implements Shape {}
static double area(Shape s) {
return switch (s) {
case Circle c -> Math.PI * c.r() * c.r();
case Rectangle r -> r.w() * r.h();
case Triangle t -> 0.5 * t.b() * t.h();
};
}ตรวจสอบความเข้าใจอย่างรวดเร็ว
เมื่อใดที่คลาสภายใน (ไม่ใช่สแตติก) เป็นตัวเลือกที่ดีกว่าคลาสซ้อนแบบสแตติก
ทบทวน: การเลือกกลยุทธ์การซ้อนที่เหมาะสม
ประเด็นสำคัญ:
- ระดับบนสุด: ประเภทสาธารณะที่ใช้อย่างกว้างขวางทั่วทั้งฐานโค้ด
- ซ้อนแบบสแตติก: จัดกลุ่มตามตรรกะกับคลาสภายนอก และไม่จำเป็นต้องใช้อินสแตนซ์ภายนอก
- คลาสภายใน: เชื่อมโยงอย่างมากกับอินสแตนซ์ภายนอก และเข้าถึงสมาชิกส่วนตัว
- คลาสภายในเมธอด: จำกัดขอบเขตอยู่ในเมธอด และซับซ้อนพอสำหรับหลายเมธอด
- คลาสนิรนาม: ใช้ครั้งเดียว รวมการประกาศและการสร้างอินสแตนซ์ไว้ด้วยกัน
- แลมบ์ดา: สะอาดที่สุดสำหรับอินเทอร์เฟซแบบ SAM ควรพิจารณาเมื่อต้องการแทนที่คลาสนิรนาม
คำถามที่พบบ่อย
บทเรียน “การเลือกกลยุทธ์การซ้อนคลาสที่เหมาะสม” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การเลือกกลยุทธ์การซ้อนคลาสที่เหมาะสม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเลือกกลยุทธ์การซ้อนคลาสที่เหมาะสม”
ตัดสินใจเลือกรูปแบบคลาสซ้อนโดยพิจารณาจากการเชื่อมโยง ความต้องการด้านการเข้าถึง และความอ่านง่าย คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การเลือกกลยุทธ์การซ้อนคลาสที่เหมาะสม” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- คลาสซ้อนแบบ Static
- คลาสภายในและการเข้าถึงคลาสภายนอก
- คลาสเฉพาะที่และคลาสนิรนาม
- การเลือกกลยุทธ์การซ้อนคลาสที่เหมาะสม