Constructor กับการกำหนดค่าเริ่มต้น

บทนำ: ปัญหาของการ Initialize ข้อมูล

จนถึงตอนนี้ เราสร้าง object แล้ว attributes ยังว่างเปล่า

java// ❌ ปัญหา: Object สร้างเสร็จแต่ยังไม่มี data
public class Student {
    private String name;
    private double gpa;
    private int year;
}

// สร้าง object
Student student = new Student();

// ต้อง set ค่าเอง (จำเบื่อ + ลืมได้)
student.setName("John");
student.setGPA(3.75);
student.setYear(2);

// ❌ ถ้า forget ชุมพล ข้อมูลจะ invalid
Student incomplete = new Student();
// incomplete.name = null, gpa = 0, year = 0 (default values)

ปัญหา:

  • ❌ ต้อง set ค่าหลายครั้ง
  • ❌ ลืมได้ → object invalid
  • ❌ Code ยาว + error-prone

Constructor คืออะไร?

Constructor = method พิเศษที่เรียกอัตโนมัติ เมื่อสร้าง object

textConstructor มีลักษณะพิเศษ:
1. ชื่อเหมือน class name
2. ไม่มี return type (ไม่ใช่ void)
3. ถูกเรียกโดยอัตโนมัติตอน new
4. ใช้ initialize data

Syntax: การเขียน Constructor

java[access modifier] ClassName(parameters) {
    // initialize code
}

ตัวอย่าง:
public Student(String name, double gpa, int year) {
    this.name = name;
    this.gpa = gpa;
    this.year = year;
}

ตัวอย่างที่ 1: Constructor พื้นฐาน

javapublic class Student {
    private String name;
    private double gpa;
    private int year;
    
    // Constructor
    public Student(String name, double gpa, int year) {
        this.name = name;
        this.gpa = gpa;
        this.year = year;
    }
    
    public void displayInfo() {
        System.out.printf("Name: %s | GPA: %.2f | Year: %d\n",
                         name, gpa, year);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        // ✓ Constructor ทำให้ data initialize เลย
        Student student = new Student("John", 3.75, 2);
        
        student.displayInfo();  // Name: John | GPA: 3.75 | Year: 2
    }
}

ข้อดี:

  • ✓ Object สร้างเสร็จ data พร้อม
  • ✓ ไม่ต้อง set ค่าแยก
  • ✓ ไม่ลืม initialize

Constructor ด้วย Validation

ตัวอย่างที่ 2: Constructor ที่ตรวจสอบข้อมูล

javapublic class BankAccount {
    private String accountNumber;
    private String accountHolder;
    private double balance;
    
    // Constructor ที่มี validation
    public BankAccount(String accountNumber, String accountHolder, double initialBalance) {
        // Validation 1: accountNumber
        if (accountNumber == null || accountNumber.isEmpty()) {
            throw new IllegalArgumentException("Account number cannot be empty");
        }
        
        // Validation 2: accountHolder
        if (accountHolder == null || accountHolder.isEmpty()) {
            throw new IllegalArgumentException("Account holder cannot be empty");
        }
        
        // Validation 3: initialBalance
        if (initialBalance < 0) {
            throw new IllegalArgumentException("Initial balance cannot be negative");
        }
        
        // Initialize (หลังผ่าน validation ทั้งหมด)
        this.accountNumber = accountNumber;
        this.accountHolder = accountHolder;
        this.balance = initialBalance;
    }
    
    public void displayInfo() {
        System.out.printf("Account: %s | Holder: %s | Balance: %.2f\n",
                         accountNumber, accountHolder, balance);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        System.out.println("=== Valid Account ===");
        BankAccount account = new BankAccount("ACC001", "John Doe", 50000);
        account.displayInfo();
        
        System.out.println("\n=== Invalid Account (negative balance) ===");
        try {
            BankAccount invalid = new BankAccount("ACC002", "Jane", -5000);
        } catch (IllegalArgumentException e) {
            System.out.println("Error: " + e.getMessage());
        }
        
        System.out.println("\n=== Invalid Account (empty holder) ===");
        try {
            BankAccount invalid = new BankAccount("ACC003", "", 50000);
        } catch (IllegalArgumentException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Output:

text=== Valid Account ===
Account: ACC001 | Holder: John Doe | Balance: 50000.00

=== Invalid Account (negative balance) ===
Error: Initial balance cannot be negative

=== Invalid Account (empty holder) ===
Error: Account holder cannot be empty

Constructor vs Setter

ความต่างกัน

text┌──────────────────┬──────────────────┬──────────────────┐
│                  │ Constructor      │ Setter           │
├──────────────────┼──────────────────┼──────────────────┤
│ เรียกเมื่อ      │ new object       │ โปรแกรม call     │
│ ที่มา            │ initialization   │ change value     │
│ บังคับ           │ ต้องใช้          │ optional         │
│ ใช้              │ วัน initialize   │ วัน update       │
└──────────────────┴──────────────────┴──────────────────┘

ตัวอย่างที่ 3: Constructor vs Setter

javapublic class Product {
    private String productID;
    private String productName;
    private double price;
    private int quantity;
    
    // Constructor: initialize ครั้งแรก
    public Product(String id, String name, double price, int qty) {
        setProductID(id);
        setProductName(name);
        setPrice(price);
        setQuantity(qty);
    }
    
    // Setter: update ภายหลัง
    
    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 qty) {
        if (qty < 0) {
            throw new IllegalArgumentException("Quantity cannot be negative");
        }
        this.quantity = qty;
    }
    
    public void displayInfo() {
        System.out.printf("ID: %s | Name: %s | Price: %.2f | Qty: %d\n",
                         productID, productName, price, quantity);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        // Constructor: ให้ค่าเมื่อ initialize
        Product laptop = new Product("P001", "Laptop", 25000, 10);
        laptop.displayInfo();
        
        // Setter: update ภายหลัง
        laptop.setPrice(24000);  // ลดราคา
        laptop.setQuantity(15);  // เพิ่มสต็อก
        laptop.displayInfo();
    }
}

Constructor ด้วยการ Assign Complex Objects

ตัวอย่างที่ 4: Initialize Collections

javaimport java.util.ArrayList;
import java.util.List;

public class Course {
    private String courseID;
    private String courseName;
    private List<String> studentList;  // Collection
    
    // Constructor ที่ initialize collection
    public Course(String id, String name) {
        this.courseID = id;
        this.courseName = name;
        this.studentList = new ArrayList<>();  // ✓ Initialize empty list
    }
    
    // Business methods
    public void addStudent(String studentName) {
        if (studentName == null || studentName.isEmpty()) {
            throw new IllegalArgumentException("Student name cannot be empty");
        }
        this.studentList.add(studentName);
        System.out.println("✓ Added: " + studentName);
    }
    
    public void displayStudents() {
        System.out.printf("Course: %s | Students: %s\n", courseName, studentList);
    }
    
    public int getStudentCount() {
        return studentList.size();
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        // Constructor initialize empty list
        Course course = new Course("CS101", "Object-Oriented Programming");
        
        course.addStudent("John");
        course.addStudent("Jane");
        course.addStudent("Bob");
        
        course.displayStudents();
        System.out.println("Total: " + course.getStudentCount());
    }
}

Output:

text✓ Added: John
✓ Added: Jane
✓ Added: Bob
Course: Object-Oriented Programming | Students: [John, Jane, Bob]
Total: 3

Constructor ที่เรียก Helper Methods

ตัวอย่างที่ 5: Constructor เรียก Private Methods

javapublic class Configuration {
    private String databaseURL;
    private int portNumber;
    private String logLevel;
    private boolean isInitialized;
    
    // Constructor
    public Configuration(String dbURL, int port, String logLevel) {
        setDatabaseURL(dbURL);      // เรียก setter (ที่มี validation)
        setPortNumber(port);
        setLogLevel(logLevel);
        initializeSystem();         // เรียก helper method
    }
    
    // Setter (with validation)
    private void setDatabaseURL(String url) {
        if (url == null || !url.startsWith("jdbc:")) {
            throw new IllegalArgumentException("Invalid database URL");
        }
        this.databaseURL = url;
    }
    
    private void setPortNumber(int port) {
        if (port < 1000 || port > 9999) {
            throw new IllegalArgumentException("Port must be between 1000-9999");
        }
        this.portNumber = port;
    }
    
    private void setLogLevel(String level) {
        if (!level.matches("DEBUG|INFO|WARN|ERROR")) {
            throw new IllegalArgumentException("Invalid log level");
        }
        this.logLevel = level;
    }
    
    // Helper method - called from constructor
    private void initializeSystem() {
        System.out.println("[System Init] Connecting to: " + databaseURL);
        System.out.println("[System Init] Port: " + portNumber);
        System.out.println("[System Init] Log level: " + logLevel);
        this.isInitialized = true;
        System.out.println("[System Init] ✓ System initialized");
    }
    
    public void displayConfig() {
        System.out.printf("DB: %s | Port: %d | Log: %s\n",
                         databaseURL, portNumber, logLevel);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        System.out.println("=== Creating Configuration ===");
        Configuration config = new Configuration("jdbc:mysql://localhost", 3306, "INFO");
        
        System.out.println("\n=== Config Details ===");
        config.displayConfig();
    }
}

Output:

text=== Creating Configuration ===
[System Init] Connecting to: jdbc:mysql://localhost
[System Init] Port: 3306
[System Init] Log level: INFO
[System Init] ✓ System initialized

=== Config Details ===
DB: jdbc:mysql://localhost | Port: 3306 | Log: INFO

Object Initialization Sequence

ลำดับการทำงาน

text1. new Student()
   ↓
2. Allocate memory ใน Heap
   ↓
3. Initialize attributes ด้วยค่า default
   (String = null, int = 0, double = 0.0, boolean = false)
   ↓
4. Constructor code ทำงาน
   ↓
5. Object ready to use

ตัวอย่างที่ 6: ดูการ Initialize

javapublic class InitializationOrder {
    private String name;           // default = null
    private int age;               // default = 0
    private double gpa;            // default = 0.0
    private boolean isActive;      // default = false
    
    public InitializationOrder(String name, int age) {
        System.out.println("Constructor started");
        System.out.println("Before assignment - name: " + this.name);
        System.out.println("Before assignment - age: " + this.age);
        
        this.name = name;
        this.age = age;
        
        System.out.println("After assignment - name: " + this.name);
        System.out.println("After assignment - age: " + this.age);
    }
    
    public void displayInfo() {
        System.out.printf("Name: %s | Age: %d | GPA: %.2f | Active: %s\n",
                         name, age, gpa, isActive);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        System.out.println("=== Creating Object ===\n");
        InitializationOrder obj = new InitializationOrder("John", 25);
        
        System.out.println("\n=== Display Info ===");
        obj.displayInfo();
    }
}

Output:

text=== Creating Object ===

Constructor started
Before assignment - name: null
Before assignment - age: 0
After assignment - name: John
After assignment - age: 25

=== Display Info ===
Name: John | Age: 25 | GPA: 0.00 | Active: false

Constructor ด้วย Default Values

ตัวอย่างที่ 7: Constructor กับ Default Values

javapublic class User {
    private String username;
    private String password;
    private int accountStatus;        // 0=new, 1=active, 2=suspended
    private long createdTime;
    private int loginCount;
    
    public User(String username, String password) {
        this.username = username;
        this.password = password;
        this.accountStatus = 0;        // NEW account
        this.createdTime = System.currentTimeMillis();
        this.loginCount = 0;           // No login yet
        
        System.out.println("✓ New user created: " + username);
    }
    
    public void login() {
        this.accountStatus = 1;        // Mark as active
        this.loginCount++;
    }
    
    public void displayInfo() {
        System.out.printf("User: %s | Status: %d | Logins: %d | Created: %d\n",
                         username, accountStatus, loginCount, createdTime);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        // Constructor ตั้ง default values
        User user = new User("john_doe", "password123");
        user.displayInfo();
        
        System.out.println("\n=== After Login ===");
        user.login();
        user.displayInfo();
    }
}

Best Practices: Constructor Design

1. Validate ทุกค่าที่ input

java// ✓ ดี
public Student(String id, String name, double gpa) {
    if (id == null || id.isEmpty()) {
        throw new IllegalArgumentException("ID cannot be empty");
    }
    if (gpa < 0 || gpa > 4.0) {
        throw new IllegalArgumentException("GPA must be 0-4.0");
    }
    this.id = id;
    this.name = name;
    this.gpa = gpa;
}

// ❌ ไม่ดี
public Student(String id, String name, double gpa) {
    this.id = id;        // No validation
    this.name = name;
    this.gpa = gpa;
}

2. Initialize ALL attributes

java// ✓ ดี
public class Order {
    private String orderID;
    private double totalAmount;
    private List<Item> items;
    private long createdTime;
    
    public Order(String id) {
        this.orderID = id;
        this.totalAmount = 0;
        this.items = new ArrayList<>();     // ✓ Initialize
        this.createdTime = System.currentTimeMillis();
    }
}

// ❌ ไม่ดี
public class Order {
    private String orderID;
    private double totalAmount;
    private List<Item> items;
    
    public Order(String id) {
        this.orderID = id;
        // totalAmount not initialized
        // items = null (NullPointerException later!)
    }
}

3. Keep it Simple

java// ✓ ดี: Constructor ง่ายๆ
public class Point {
    private double x;
    private double y;
    
    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

// ⚠️ ไม่ดี: Constructor ยุ่งเหยิง
public class Point {
    private double x;
    private double y;
    
    public Point(double x, double y) {
        // Business logic ยุ่งๆ
        loadConfigFile();
        connectToDatabase();
        calculateDistances();
        // ...
    }
}

4. Call Setters ใน Constructor

java// ✓ ดี: ใช้ setter ให้ reuse validation
public class Account {
    private double balance;
    
    public Account(double initialBalance) {
        setBalance(initialBalance);  // ← ใช้ setter
    }
    
    public void setBalance(double balance) {
        if (balance < 0) {
            throw new IllegalArgumentException("Cannot be negative");
        }
        this.balance = balance;
    }
}

// ❌ ไม่ดี: validation code ซ้ำ
public class Account {
    private double balance;
    
    public Account(double initialBalance) {
        if (initialBalance < 0) {  // ← ซ้ำกับใน setter
            throw new IllegalArgumentException("Cannot be negative");
        }
        this.balance = initialBalance;
    }
    
    public void setBalance(double balance) {
        if (balance < 0) {  // ← ซ้ำ
            throw new IllegalArgumentException("Cannot be negative");
        }
        this.balance = balance;
    }
}

ตัวอย่างสุดท้าย: Complete Class ด้วย Constructor

javapublic class Employee {
    private String employeeID;
    private String name;
    private String department;
    private double salary;
    private int startYear;
    
    // Constructor
    public Employee(String id, String name, String dept, double salary, int year) {
        // Validation
        if (id == null || id.isEmpty()) {
            throw new IllegalArgumentException("Employee ID required");
        }
        if (name == null || name.isEmpty()) {
            throw new IllegalArgumentException("Name required");
        }
        if (salary < 0) {
            throw new IllegalArgumentException("Salary cannot be negative");
        }
        if (year < 2000 || year > 2025) {
            throw new IllegalArgumentException("Invalid start year");
        }
        
        // Assignment
        this.employeeID = id;
        this.name = name;
        this.department = dept;
        this.salary = salary;
        this.startYear = year;
        
        // Log
        System.out.printf("✓ Employee created: %s (%s)\n", name, id);
    }
    
    // Business methods
    public void giveSalaryIncrease(double percentage) {
        if (percentage < 0 || percentage > 50) {
            throw new IllegalArgumentException("Invalid percentage");
        }
        double increment = this.salary * percentage / 100;
        this.salary += increment;
        System.out.printf("✓ Salary increased by %.1f%% to %.2f\n", 
                         percentage, this.salary);
    }
    
    public int getYearsOfService() {
        return 2025 - this.startYear;
    }
    
    public void displayInfo() {
        System.out.printf("ID: %s | Name: %s | Dept: %s | Salary: %.2f | Years: %d\n",
                         employeeID, name, department, salary, getYearsOfService());
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        System.out.println("=== Creating Employees ===");
        Employee emp1 = new Employee("E001", "John Smith", "Engineering", 50000, 2020);
        Employee emp2 = new Employee("E002", "Jane Doe", "Marketing", 45000, 2022);
        
        System.out.println("\n=== Employee Details ===");
        emp1.displayInfo();
        emp2.displayInfo();
        
        System.out.println("\n=== Salary Increase ===");
        emp1.giveSalaryIncrease(10);
        emp1.displayInfo();
        
        System.out.println("\n=== Invalid Creation Attempt ===");
        try {
            Employee invalid = new Employee("E003", "", "HR", -5000, 2025);
        } catch (IllegalArgumentException e) {
            System.out.println("❌ Error: " + e.getMessage());
        }
    }
}

Output:

text=== Creating Employees ===
✓ Employee created: John Smith (E001)
✓ Employee created: Jane Doe (E002)

=== Employee Details ===
ID: E001 | Name: John Smith | Dept: Engineering | Salary: 50000.00 | Years: 5
ID: E002 | Name: Jane Doe | Dept: Marketing | Salary: 45000.00 | Years: 3

=== Salary Increase ===
✓ Salary increased by 10.0% to 55000.00
ID: E001 | Name: John Smith | Dept: Engineering | Salary: 55000.00 | Years: 5

=== Invalid Creation Attempt ===
❌ Error: Name required

สรุป: Constructor

text┌──────────────────────────────────────────────┐
│  Constructor: การกำหนดค่าเริ่มต้น          │
├──────────────────────────────────────────────┤
│                                              │
│  ✓ Constructor คืออะไร                     │
│    └─ Method พิเศษเรียกอัตโนมัติตอน new   │
│                                              │
│  ✓ ใช้ทำอะไร                               │
│    ├─ Initialize attributes                │
│    ├─ Validate input values                │
│    ├─ Initialize collections               │
│    └─ Setup system                         │
│                                              │
│  ✓ Best Practices                          │
│    ├─ Validate ทุกค่า                      │
│    ├─ Initialize ALL attributes            │
│    ├─ Keep constructor simple              │
│    ├─ Call setters (reuse validation)      │
│    └─ Handle errors gracefully             │
│                                              │
│  ✓ ประโยชน์                                │
│    ├─ Object ready ตั้งแต่เริ่ม             │
│    ├─ Ensure valid state                   │
│    ├─ Reduce boilerplate code              │
│    └─ Prevent bugs                         │
│                                              │
└──────────────────────────────────────────────┘