บทนำ: ปัญหาของการเปิดเผยข้อมูล
จนถึงตอนนี้ เราเขียนโปรแกรมโดย ให้ใครก็ได้เข้าถึง attributes ได้
java// ❌ ปัญหา: Attributes เปิดเผย
public class BankAccount {
public double balance; // ใครก็ถ้อนเงินให้เชื่อมแบบไม่ถูกต้อง!
}
// ใช้งาน
BankAccount account = new BankAccount();
account.balance = 50000;
account.balance = -10000; // !!!! ยอดเงินติดลบ - ผิด!
account.balance = 999999999; // !!!! เงินเยอะขึ้นโดยไม่ฝาก - ผิด!
ปัญหา:
- ❌ ใครก็เปลี่ยนแปลงข้อมูล โดยไม่ตรวจสอบ
- ❌ ไม่ได้บ้านหมั้น (ไม่มีเงื่อนไข)
- ❌ ข้อมูลสามารถ ทำให้ inconsistent (ไม่สอดคล้องกัน)
- ❌ ไม่มีการบันทึก (audit trail) ว่าใครเปลี่ยนข้อมูล
ยาวไปอยากเลือกอ่าน
- บทนำ: ปัญหาของการเปิดเผยข้อมูล
- Encapsulation คืออะไร?
- ตัวอย่าง: Encapsulation ในชีวิตจริง
- ตัวอย่าง 1: ATM
- ตัวอย่าง 2: Car Engine
- ประโยชน์ของ Encapsulation
- 1. Data Integrity (ความถูกต้องของข้อมูล)
- 2. Flexibility (ความยืดหยุ่น)
- 3. Security (ความปลอดภัย)
- 4. Maintainability (ง่ายต่อการดูแล)
- Analogy: Encapsulation เหมือนบ้าน
- หลักการ 3 ประการของ Encapsulation
- 1. Hide (ซ่อน)
- 2. Restrict (จำกัด)
- 3. Validate (ตรวจสอบ)
- ตัวอย่างที่ 1: Student Class ที่ไม่ Encapsulated
- ตัวอย่างที่ 2: Student Class ที่ Encapsulated (ดี)
- ตัวอย่างที่ 3: BankAccount ที่ Encapsulated
- ตัวอย่างที่ 4: Product Inventory System
- หลักการของ Encapsulation Summary
- ตัวอย่างที่ 5: Temperature Class ที่ซ่อน Internal Representation
- ข้อสรุป: ทำไมต้อง Encapsulation
- คำแนะนำ: เขียน Encapsulation ที่ดี
Encapsulation คืออะไร?
Encapsulation (หลีกเหลี่ยม) คือ หลักการซ่อน:
- ซ่อนข้อมูลภายใน (hide internal data)
- เปิด interface ทีละส่วน (expose only necessary operations)
- ควบคุมการเข้าถึง (validate access)
คำนำ: เหมือนกล่องดำของเครื่องบิน
- ภายในมี electronic ที่ซับซ้อน (ซ่อนไว้)
- แต่ภายนอกมี switch/button (interface) ที่ใช้งาน
ตัวอย่าง: Encapsulation ในชีวิตจริง
ตัวอย่าง 1: ATM
text❌ ไม่ Encapsulation:
─────────────────────────
ATM: "ที่นี่ที่เลขบัญชี, ที่นี่ account, เปลี่ยนเงินได้เอง!"
User: เข้าใจได้ ฉันเปลี่ยน balance = 999999 ได้!
✓ Encapsulation:
──────────────────────────
ATM: "บอกฉัน: เบอร์บัตร, PIN, จำนวนเงิน"
"ฉันจะทำการตรวจสอบและถอนเงินให้"
User: "OK, ถอน 5000 บาท"
ATM: "✓ ตรวจสอบ PIN ได้"
"✓ ตรวจสอบ balance พอ"
"✓ ถอนเงินสำเร็จ"
"✓ บันทึก transaction"
ตัวอย่าง 2: Car Engine
text❌ ไม่ Encapsulation:
──────────────────────
ผู้ขับขี่: "ฉันเปิด carburetor, ปรับ timing valve, ..."
(ต้องรู้ลายละเอียด)
✓ Encapsulation:
──────────────────
ผู้ขับขี่: "ฉันเหยียบ accelerator, ปั่นกุญแจ"
Engine: "ฉันจะทำทุกอย่าง"
"✓ ปรับ fuel injection"
"✓ ปรับ ignition timing"
"✓ ปรับ air intake"
ประโยชน์ของ Encapsulation
1. Data Integrity (ความถูกต้องของข้อมูล)
java// ✓ ด้วย Encapsulation
public class Student {
private double gpa; // ซ่อน
public void setGPA(double newGPA) {
if (newGPA >= 0 && newGPA <= 4.0) {
this.gpa = newGPA; // ✓ ตรวจสอบแล้ว
} else {
System.out.println("Error: GPA must be between 0-4.0");
}
}
public double getGPA() {
return this.gpa;
}
}
// ใช้งาน
Student student = new Student();
student.setGPA(3.75); // ✓ OK
student.setGPA(5.0); // ❌ Error: GPA must be between 0-4.0
student.setGPA(-1); // ❌ Error: GPA must be between 0-4.0
ประโยชน์: ข้อมูล ไม่เคยผิด เพราะมี validation
2. Flexibility (ความยืดหยุ่น)
java// ❌ ไม่ Encapsulation: เปลี่ยนใจยาก
public class Person {
public String fullName; // เก็บแบบเต็มชื่อ
}
// ต่อมา: ต้องแยก firstName, lastName
// → ต้องแก้ไขทุก code ที่ใช้ fullName
// ✓ Encapsulation: เปลี่ยนใจได้
public class Person {
private String firstName;
private String lastName;
public void setFullName(String first, String last) {
this.firstName = first;
this.lastName = last;
}
public String getFullName() {
return firstName + " " + lastName;
}
}
// ใช้งาน: เหมือนเดิม (method interface เดียวกัน)
person.setFullName("John", "Doe");
String name = person.getFullName();
ประโยชน์: เปลี่ยน internal implementation แต่ interface ไม่เปลี่ยน
3. Security (ความปลอดภัย)
java// ❌ ไม่ Encapsulation: ข้อมูลสำคัญเปิดเผย
public class Account {
public String password;
}
// ใครก็ได้อ่าน password ได้!
Account account = new Account();
System.out.println(account.password); // ❌ Hacked!
// ✓ Encapsulation: ซ่อนข้อมูลสำคัญ
public class Account {
private String password; // ซ่อน
public boolean verifyPassword(String input) {
return password.equals(input); // ✓ ตรวจสอบเท่านั้น
}
public void changePassword(String oldPwd, String newPwd) {
if (verifyPassword(oldPwd)) {
this.password = newPwd; // ✓ มี verification
}
}
}
// ใช้งาน: ไม่ได้อ่านข้อมูลจริง
if (account.verifyPassword("myPassword")) {
System.out.println("Correct!");
}
ประโยชน์: ข้อมูลสำคัญ ไม่สามารถอ่านได้ โดยตรง
4. Maintainability (ง่ายต่อการดูแล)
java// ❌ ไม่ Encapsulation: เปลี่ยนได้ยาก
public class Temperature {
public double celsius; // เก็บอุณหภูมิเป็น Celsius
}
// Code ที่ใช้: เก็บหลายที่ๆ
double temp = tempObject.celsius;
tempObject.celsius = 25;
// ต่อมา: ต้องเปลี่ยนเป็น Kelvin
// → ต้องค้นหาทุกที่ที่เข้าถึง celsius และแก้ไข
// ✓ Encapsulation: เปลี่ยนได้ง่าย
public class Temperature {
private double kelvin; // เปลี่ยนเป็น Kelvin ภายใน
public double getCelsius() {
return kelvin - 273.15;
}
public void setCelsius(double celsius) {
this.kelvin = celsius + 273.15;
}
}
// ใช้งาน: เหมือนเดิม
double temp = tempObject.getCelsius();
tempObject.setCelsius(25);
ประโยชน์: เปลี่ยน internal representation โดย ผู้ใช้ไม่รู้
Analogy: Encapsulation เหมือนบ้าน
text❌ บ้านไม่มี Encapsulation:
────────────────────────────
┌─────────────────────────────┐
│ Open House! │
│ ไม่มีผนัง, ไม่มีประตู │
│ ใครก็เข้าได้ ทำอะไรก็ได้ │
│ - สวิช light ปิด/เปิด │
│ - เปลี่ยน furniture │
│ - กัดขนมใน fridge │
│ - เข้าห้องนอนได้ │
│ - อ่านเอกสารส่วนตัว │
│ ⚠️ ยุ่ม! ความเป็นส่วนตัวไม่มี!
└─────────────────────────────┘
✓ บ้านมี Encapsulation:
──────────────────────────
┌─────────────────────────────┐
│ Private House! │
│ ┌─ ประตูด้านนอก │
│ │ (gate - ต้องใช้ keycard) │
│ │ │
│ ├─ ประตูห้องรับแขก │
│ │ (controlled access) │
│ │ │
│ ├─ ประตูห้องอื่น │
│ │ (locked - เฉพาะครอบครัว)│
│ │ │
│ ├─ ประตูห้องนอน │
│ │ (ส่วนตัว - ปิดสนิท) │
│ │ │
│ └─ Safe ในห้องนอน │
│ (ข้อมูลสำคัญซ่อน) │
│ │
│ ✓ ส่วนตัวได้ + ปลอดภัย! │
└─────────────────────────────┘
หลักการ 3 ประการของ Encapsulation
1. Hide (ซ่อน)
java// ❌ เปิดเผย
public class Student {
public String name;
public int age;
public double gpa;
}
// ✓ ซ่อน
public class Student {
private String name; // ✓ ซ่อน
private int age; // ✓ ซ่อน
private double gpa; // ✓ ซ่อน
}
วิธี: ใช้ private
2. Restrict (จำกัด)
java// ✓ จำกัดวิธีการเข้าถึง
public class Student {
private double gpa;
// ✓ เข้าถึงได้ผ่าน setter เท่านั้น
public void setGPA(double newGPA) {
if (newGPA >= 0 && newGPA <= 4.0) {
this.gpa = newGPA;
}
}
// ✓ อ่านค่าได้ผ่าน getter เท่านั้น
public double getGPA() {
return this.gpa;
}
}
// ใช้งาน: เข้าถึงผ่าน methods เท่านั้น
student.setGPA(3.75);
double gpa = student.getGPA();
// ❌ ไม่ได้:
// student.gpa = 5.0; // ERROR! private
วิธี: ให้ getter/setter จำกัด
3. Validate (ตรวจสอบ)
java// ✓ ตรวจสอบเมื่อเปลี่ยนแปลง
public class BankAccount {
private double balance;
public void setBalance(double newBalance) {
if (newBalance < 0) {
throw new IllegalArgumentException("Balance cannot be negative");
}
this.balance = newBalance;
}
public void withdraw(double amount) {
if (amount > this.balance) {
throw new IllegalArgumentException("Insufficient balance");
}
this.balance -= amount;
}
public double getBalance() {
return this.balance;
}
}
// ใช้งาน
BankAccount account = new BankAccount();
account.setBalance(50000);
account.withdraw(30000); // ✓ OK
account.withdraw(25000); // ❌ Error: Insufficient balance
วิธี: เพิ่ม validation logic ใน setter
ตัวอย่างที่ 1: Student Class ที่ไม่ Encapsulated
java// ❌ ไม่ Encapsulation
public class StudentBad {
public String studentID;
public String name;
public double gpa;
public int year;
public void study() {
gpa += 0.1;
}
}
// ปัญหา:
public class Main {
public static void main(String[] args) {
StudentBad student = new StudentBad();
// ❌ ก็ได้ set ค่า invalid
student.studentID = null; // null!
student.name = ""; // string ว่าง!
student.gpa = 10.5; // GPA > 4.0!
student.year = 0; // ปี 0?
// ❌ ก็ได้ใช้ method ไม่ถูกต้อง
for (int i = 0; i < 1000; i++) {
student.study(); // GPA = 100 + !!!
}
}
}
ตัวอย่างที่ 2: Student Class ที่ Encapsulated (ดี)
java// ✓ Encapsulation
public class StudentGood {
private String studentID;
private String name;
private double gpa;
private int year;
// Constructor ที่มี validation
public StudentGood(String studentID, String name, double gpa, int year) {
setStudentID(studentID);
setName(name);
setGPA(gpa);
setYear(year);
}
// ===== Getters =====
public String getStudentID() {
return studentID;
}
public String getName() {
return name;
}
public double getGPA() {
return gpa;
}
public int getYear() {
return year;
}
// ===== Setters (มี Validation) =====
public void setStudentID(String id) {
if (id == null || id.isEmpty()) {
throw new IllegalArgumentException("Student ID cannot be null or empty");
}
this.studentID = id;
}
public void setName(String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Name cannot be null or empty");
}
this.name = name;
}
public void setGPA(double gpa) {
if (gpa < 0 || gpa > 4.0) {
throw new IllegalArgumentException("GPA must be between 0 and 4.0");
}
this.gpa = gpa;
}
public void setYear(int year) {
if (year < 1 || year > 4) {
throw new IllegalArgumentException("Year must be between 1 and 4");
}
this.year = year;
}
// ===== Business Methods =====
public void study() {
double newGPA = gpa + 0.1;
if (newGPA > 4.0) {
newGPA = 4.0; // Cap at 4.0
}
this.gpa = newGPA;
}
public void displayInfo() {
System.out.printf("ID: %s, Name: %s, GPA: %.2f, Year: %d\n",
studentID, name, gpa, year);
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
// ✓ การสร้าง valid object
StudentGood student = new StudentGood("6501001", "John", 3.75, 2);
student.displayInfo(); // ID: 6501001, Name: John, GPA: 3.75, Year: 2
// ✓ ใช้ getter
System.out.println("GPA: " + student.getGPA()); // 3.75
// ✓ ใช้ setter ที่ safe
student.study();
System.out.println("After study: " + student.getGPA()); // 3.85
// ❌ ไม่ได้ set ค่า invalid
try {
student.setGPA(10.5); // ❌ Error!
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
// ❌ ไม่ได้เข้าถึง private attributes
// student.gpa = 5.0; // ERROR! private
// ❌ ไม่ได้สร้าง invalid object
try {
StudentGood bad = new StudentGood("", "John", 3.75, 2); // ❌ Error!
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
ตัวอย่างที่ 3: BankAccount ที่ Encapsulated
javapublic class BankAccount {
private String accountNumber;
private String accountHolder;
private double balance;
private int transactions = 0; // นับจำนวน transaction
public BankAccount(String accountNumber, String accountHolder, double initialBalance) {
if (accountNumber == null || accountNumber.isEmpty()) {
throw new IllegalArgumentException("Account number cannot be empty");
}
if (accountHolder == null || accountHolder.isEmpty()) {
throw new IllegalArgumentException("Account holder cannot be empty");
}
if (initialBalance < 0) {
throw new IllegalArgumentException("Initial balance cannot be negative");
}
this.accountNumber = accountNumber;
this.accountHolder = accountHolder;
this.balance = initialBalance;
}
// ===== Getters =====
public String getAccountNumber() {
return accountNumber;
}
public String getAccountHolder() {
return accountHolder;
}
public double getBalance() {
return balance;
}
public int getTransactionCount() {
return transactions;
}
// ===== Business Methods (ไม่มี direct setBalance) =====
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Deposit amount must be positive");
}
this.balance += amount;
this.transactions++;
System.out.printf("[DEPOSIT] Amount: %.2f, New Balance: %.2f\n", amount, balance);
}
public void withdraw(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Withdraw amount must be positive");
}
if (amount > this.balance) {
throw new IllegalArgumentException("Insufficient balance. Current: " + balance);
}
this.balance -= amount;
this.transactions++;
System.out.printf("[WITHDRAW] Amount: %.2f, New Balance: %.2f\n", amount, balance);
}
public void transfer(BankAccount recipient, double amount) {
if (recipient == null) {
throw new IllegalArgumentException("Recipient account cannot be null");
}
if (amount <= 0) {
throw new IllegalArgumentException("Transfer amount must be positive");
}
if (amount > this.balance) {
throw new IllegalArgumentException("Insufficient balance for transfer");
}
this.withdraw(amount); // ลด balance ของ this
recipient.deposit(amount); // เพิ่ม balance ของ recipient
System.out.printf("[TRANSFER] From %s to %s: %.2f\n",
this.accountNumber, recipient.accountNumber, amount);
}
public void displayInfo() {
System.out.printf("Account: %s | Holder: %s | Balance: %.2f | Transactions: %d\n",
accountNumber, accountHolder, balance, transactions);
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
BankAccount account1 = new BankAccount("ACC001", "John", 50000);
BankAccount account2 = new BankAccount("ACC002", "Jane", 30000);
System.out.println("=== Initial State ===");
account1.displayInfo(); // Balance: 50000, Transactions: 0
account2.displayInfo(); // Balance: 30000, Transactions: 0
System.out.println("\n=== Deposit ===");
account1.deposit(10000);
account1.displayInfo(); // Balance: 60000, Transactions: 1
System.out.println("\n=== Withdraw ===");
account1.withdraw(5000);
account1.displayInfo(); // Balance: 55000, Transactions: 2
System.out.println("\n=== Transfer ===");
account1.transfer(account2, 20000);
System.out.println("\n=== Final State ===");
account1.displayInfo(); // Balance: 35000, Transactions: 3
account2.displayInfo(); // Balance: 50000, Transactions: 1
System.out.println("\n=== Error Handling ===");
try {
account1.withdraw(50000); // ❌ Insufficient
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
try {
account1.setBalance(-1000); // ❌ ERROR! ไม่มี setBalance
} catch (Exception e) {
System.out.println("Error: Cannot set balance directly!");
}
}
}
Output:
text=== Initial State ===
Account: ACC001 | Holder: John | Balance: 50000.00 | Transactions: 0
Account: ACC002 | Holder: Jane | Balance: 30000.00 | Transactions: 0
=== Deposit ===
[DEPOSIT] Amount: 10000.00, New Balance: 60000.00
Account: ACC001 | Holder: John | Balance: 60000.00 | Transactions: 1
=== Withdraw ===
[WITHDRAW] Amount: 5000.00, New Balance: 55000.00
Account: ACC001 | Holder: John | Balance: 55000.00 | Transactions: 2
=== Transfer ===
[WITHDRAW] Amount: 20000.00, New Balance: 35000.00
[DEPOSIT] Amount: 20000.00, New Balance: 50000.00
[TRANSFER] From ACC001 to ACC002: 20000.00
=== Final State ===
Account: ACC001 | Holder: John | Balance: 35000.00 | Transactions: 3
Account: ACC002 | Holder: Jane | Balance: 50000.00 | Transactions: 1
=== Error Handling ===
Error: Insufficient balance for transfer. Current: 35000.0
Error: Cannot set balance directly!
ตัวอย่างที่ 4: Product Inventory System
javapublic class Product {
private String productID;
private String productName;
private double price;
private int quantity;
private double totalSold = 0; // ติดตาม
public Product(String id, String name, double price, int quantity) {
setProductID(id);
setProductName(name);
setPrice(price);
setQuantity(quantity);
}
// ===== Getters =====
public String getProductID() {
return productID;
}
public String getProductName() {
return productName;
}
public double getPrice() {
return price;
}
public int getQuantity() {
return quantity;
}
public double getTotalSold() {
return totalSold;
}
public boolean isInStock() {
return quantity > 0;
}
// ===== Setters (มี Validation) =====
public void setProductID(String id) {
if (id == null || id.isEmpty()) {
throw new IllegalArgumentException("Product ID cannot be empty");
}
this.productID = id;
}
public void setProductName(String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Product name cannot be empty");
}
this.productName = name;
}
public void setPrice(double price) {
if (price < 0) {
throw new IllegalArgumentException("Price cannot be negative");
}
this.price = price;
}
public void setQuantity(int quantity) {
if (quantity < 0) {
throw new IllegalArgumentException("Quantity cannot be negative");
}
this.quantity = quantity;
}
// ===== Business Methods =====
public void addStock(int amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Amount must be positive");
}
this.quantity += amount;
System.out.printf("[STOCK ADD] %s: Added %d units (Total: %d)\n",
productName, amount, quantity);
}
public void sell(int amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Amount must be positive");
}
if (amount > this.quantity) {
throw new IllegalArgumentException("Insufficient stock. Available: " + quantity);
}
this.quantity -= amount;
double revenue = amount * price;
this.totalSold += revenue;
System.out.printf("[SALE] %s: Sold %d units for %.2f (Total sold: %.2f)\n",
productName, amount, revenue, totalSold);
}
public void displayInfo() {
System.out.printf("ID: %s | Name: %s | Price: %.2f | Stock: %d | Total Sold: %.2f\n",
productID, productName, price, quantity, totalSold);
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
Product laptop = new Product("P001", "Laptop", 25000, 10);
Product mouse = new Product("P002", "Mouse", 500, 50);
System.out.println("=== Initial State ===");
laptop.displayInfo();
mouse.displayInfo();
System.out.println("\n=== Add Stock ===");
laptop.addStock(5);
mouse.addStock(30);
System.out.println("\n=== Sell ===");
laptop.sell(2); // ขาย laptop 2 เครื่อง
mouse.sell(20); // ขาย mouse 20 ตัว
System.out.println("\n=== State After Sales ===");
laptop.displayInfo();
mouse.displayInfo();
System.out.println("\n=== Stock Status ===");
System.out.println("Laptop in stock: " + laptop.isInStock());
System.out.println("Mouse in stock: " + mouse.isInStock());
System.out.println("\n=== Error Handling ===");
try {
laptop.sell(100); // ❌ Insufficient stock
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
try {
mouse.setPrice(-1000); // ❌ Negative price
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
หลักการของ Encapsulation Summary
text┌─────────────────────────────────────────────┐
│ Encapsulation = "Black Box" Principle │
├─────────────────────────────────────────────┤
│ │
│ HIDE (ซ่อน) │
│ ├─ Private attributes │
│ └─ Internal implementation │
│ │
│ RESTRICT (จำกัด) │
│ ├─ Public getters │
│ └─ Public setters (with validation) │
│ │
│ VALIDATE (ตรวจสอบ) │
│ ├─ Input validation │
│ ├─ Business rule enforcement │
│ └─ Data consistency │
│ │
│ RESULT (ผลลัพธ์) │
│ ├─ Data integrity │
│ ├─ Security │
│ ├─ Flexibility │
│ └─ Maintainability │
│ │
└─────────────────────────────────────────────┘
ตัวอย่างที่ 5: Temperature Class ที่ซ่อน Internal Representation
javapublic class Temperature {
// ✓ เก็บเป็น Kelvin (ภายใน)
private double kelvin;
public Temperature(double celsius) {
setCelsius(celsius); // ใช้ setter ที่มี validation
}
// ===== Expose ผ่าน Celsius =====
public double getCelsius() {
return kelvin - 273.15;
}
public void setCelsius(double celsius) {
if (celsius < -273.15) {
throw new IllegalArgumentException("Temperature cannot be below absolute zero");
}
this.kelvin = celsius + 273.15;
}
// ===== Expose ผ่าน Fahrenheit =====
public double getFahrenheit() {
return (kelvin - 273.15) * 9 / 5 + 32;
}
public void setFahrenheit(double fahrenheit) {
double celsius = (fahrenheit - 32) * 5 / 9;
setCelsius(celsius);
}
// ===== Expose ผ่าน Kelvin =====
public double getKelvin() {
return kelvin;
}
public void setKelvin(double kelvin) {
if (kelvin < 0) {
throw new IllegalArgumentException("Kelvin temperature cannot be negative");
}
this.kelvin = kelvin;
}
public void displayInfo() {
System.out.printf("C: %.2f | F: %.2f | K: %.2f\n",
getCelsius(), getFahrenheit(), getKelvin());
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
Temperature temp = new Temperature(25); // 25°C
System.out.println("=== Setting via Celsius ===");
temp.displayInfo(); // C: 25.00 | F: 77.00 | K: 298.15
System.out.println("\n=== Setting via Fahrenheit ===");
temp.setFahrenheit(100); // 100°F
temp.displayInfo(); // C: 37.78 | F: 100.00 | K: 310.93
System.out.println("\n=== Setting via Kelvin ===");
temp.setKelvin(273.15); // 0°C (freezing point of water)
temp.displayInfo(); // C: 0.00 | F: 32.00 | K: 273.15
System.out.println("\n=== Error Handling ===");
try {
temp.setCelsius(-500); // ❌ Below absolute zero
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
ประเด็นสำคัญ:
- Internal: เก็บเป็น Kelvin เท่านั้น
- Interface: expose เป็น Celsius, Fahrenheit, Kelvin
- ผู้ใช้ไม่รู้: ว่าภายในเก็บเป็น Kelvin
- Flexibility: สามารถเปลี่ยน internal representation (เช่นเป็น Celsius) โดย interface ไม่เปลี่ยน
ข้อสรุป: ทำไมต้อง Encapsulation
text❌ ไม่ Encapsulation:
────────────────────
- ข้อมูลผิด ✗
- ไม่ปลอดภัย ✗
- ยากต่อการแก้ไข ✗
- Code ซ้ำซ้อน ✗
✓ Encapsulation:
─────────────────
- ข้อมูลถูกต้อง ✓
- ปลอดภัย ✓
- ง่ายต่อการแก้ไข ✓
- Code สะอาด ✓
คำแนะนำ: เขียน Encapsulation ที่ดี
text1. ทำให้ attributes เป็น private
✓ private String name;
✗ public String name;
2. เพิ่ม getter/setter
✓ public String getName() { }
✓ public void setName(String name) { }
3. เพิ่ม validation
✓ if (name == null || name.isEmpty()) throw ...
✓ if (age < 0 || age > 150) throw ...
4. ยกเว้น constants
✓ public static final double PI = 3.14159;
✓ public static final int MAX_STUDENTS = 100;
5. ซ่อน implementation details
✓ เก็บ internal data ที่ best
✓ expose ผ่าน interface ที่ clean
