Encapsulation (การห่อหุ้ม) เป็นหลักการสำคัญของ OOP ที่ รวม Data (Attributes) และ Methods (Behaviors) ไว้ในหน่วยเดียวคือ Class และ ซ่อนรายละเอียดการทำงานภายใน (Implementation Details) ไว้จากภายนอก
หลักการหลัก
- Data Hiding: ทำ Data Members เป็น
private - Controlled Access: ให้เข้าถึงผ่าน
publicMethods (Getters/Setters) - Validation: ตรวจสอบความถูกต้องก่อนตั้งค่า
- Abstraction: ผู้ใช้ไม่ต้องรู้ว่าเก็บข้อมูลยังไง คำนวณยังไง
โค้ดตัวอย่าง: กล่องสี่เหลี่ยม (Box Volume)
#include <iostream>
using namespace std;
class Box {
private:
double length, width, height; // Data Hiding
public:
// Constructor
Box(double l = 1, double w = 1, double h = 1)
: length(l), width(w), height(h) {}
// Setters with Validation
void setLength(double l) {
if (l > 0) length = l;
else cout << "Length must be positive!" << endl;
}
void setWidth(double w) {
if (w > 0) width = w;
else cout << "Width must be positive!" << endl;
}
void setHeight(double h) {
if (h > 0) height = h;
else cout << "Height must be positive!" << endl;
}
// Getters
double getLength() const { return length; }
double getWidth() const { return width; }
double getHeight() const { return height; }
// Business Logic
double getVolume() const { return length * width * height; }
double getSurfaceArea() const { return 2 * (length*width + width*height + height*length); }
void display() const {
cout << "Box [" << length << " x " << width << " x " << height << "]" << endl;
cout << "Volume: " << getVolume() << endl;
cout << "Surface Area: " << getSurfaceArea() << endl;
}
};
int main() {
Box box1(5, 3, 2);
box1.display();
cout << "--- Change dimensions ---" << endl;
box1.setLength(10);
box1.setWidth(-5); // Validation จะป้องกัน
box1.setHeight(4);
box1.display();
return 0;
}
ผลลัพธ์
Box [5 x 3 x 2] Volume: 30 Surface Area: 62 --- Change dimensions --- Width must be positive! Box [10 x 3 x 4] Volume: 120 Surface Area: 164
ข้อดีของ Encapsulation
| ประโยชน์ | คำอธิบาย |
|---|---|
| Data Integrity | ป้องกันค่าไม่ถูกต้อง (Validation ใน Setters) |
| Flexibility | เปลี่ยน Implementation ภายในได้โดยไม่กระทบ Code ภายนอก |
| Security | ควบคุมว่าใคร Read/Write ได้บ้าง |
| Maintainability | แก้ Bug/เพิ่ม Feature ใน Class เดียว |
| Reusability | นำ Class ไปใช้งานซ้ำได้ง่าย |
| Testing | ทดสอบ Class แยกได้ (Unit Test) |
Encapsulation vs Abstraction
Encapsulation (การห่อหุ้ม)
- How - ซ่อน "รายละเอียดการทำงาน"
- ระดับ: Implementation Level
- เครื่องมือ: Access Modifiers (private/public)
- ตัวอย่าง: private data + public getters/setters
Abstraction (การสรุปทั่วไป)
- What - แสดง "สิ่งที่จำเป็น" เท่านั้น
- ระดับ: Design/Interface Level
- เครื่องมือ: Abstract Class, Interface, Pure Virtual
- ตัวอย่าง: Abstract Class Shape → draw()
การออกแบบ Class ที่ดี (Class Design Principles)
// ✓ Good Encapsulation
class BankAccount {
private:
string accountNumber;
double balance; // Private - ควบคุมผ่าน Methods
vector<Transaction> history;
public:
BankAccount(string acc) : accountNumber(acc), balance(0) {}
void deposit(double amount) { // Business Logic
if (amount > 0) {
balance += amount;
history.push_back({amount, "Deposit"});
}
}
bool withdraw(double amount) { // Business Logic + Validation
if (amount > 0 && amount <= balance) {
balance -= amount;
history.push_back({-amount, "Withdraw"});
return true;
}
return false;
}
double getBalance() const { return balance; } // Read-only
void printStatement() const; // Complex operation
};
// ✗ Bad Encapsulation
class BadAccount {
public:
double balance; // ใครก็แก้ได้ ไม่มี Validation
};
// main() { BadAccount a; a.balance = -1000000; } // ผิดได้!
Getter/Setter Patterns
// 1. Simple Getter/Setter
int getValue() const { return value; }
void setValue(int v) { value = v; }
// 2. Read-only Property (Getter only)
const string& getName() const { return name; }
// 3. Write-only (Setter only) - นادر
void setPassword(const string& pwd) { passwordHash = hash(pwd); }
// 4. Computed Property (ไม่เก็บตัวแปร)
double getArea() const { return width * height; }
// 5. Fluent Interface (Chaining)
Box& setLength(double l) { length = l; return *this; }
Box& setWidth(double w) { width = w; return *this; }
// ใช้: box.setLength(10).setWidth(5).setHeight(3);