Constructor Overloading & Chaining

บทนำ: ปัญหาของ Constructor เดียว

เมื่อเรามี Constructor เดียว บางครั้งไม่ยืดหยุ่นพอ

java// ❌ ปัญหา: บังคับให้ระบุข้อมูลทั้งหมด
public 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;
    }
}

// บังคับให้ระบุทั้งหมด
Student student = new Student("John", 3.75, 2);

// ❌ ถ้าไม่รู้ gpa? ไม่สามารถสร้างได้
// Student newbie = new Student("Jane", ???, 1);

// ❌ ถ้าต้องการแค่ชื่อ? ไม่สามารถ
// Student simple = new Student("Bob");

ปัญหา:

  • ❌ ไม่ยืดหยุ่น
  • ❌ บังคับให้มีข้อมูลครบ
  • ❌ บางครั้งต้องการเฉพาะบางค่า

Constructor Overloading คืออะไร?

Constructor Overloading = มี Constructor หลายแบบ ด้วย parameters ต่างกัน

textOverloading = ชื่อเดียวกัน + parameters ต่างกัน

ตัวอย่าง:
public Student(String name)
public Student(String name, double gpa)
public Student(String name, double gpa, int year)

← ชื่อเดียวกัน (Student) แต่ parameters ต่างกัน

Overloading: Syntax

javapublic class ClassName {
    // Constructor 1
    public ClassName(Type1 param1) {
        // ...
    }
    
    // Constructor 2 - parameters ต่างกัน
    public ClassName(Type1 param1, Type2 param2) {
        // ...
    }
    
    // Constructor 3 - parameters ต่างกัน
    public ClassName(Type1 param1, Type2 param2, Type3 param3) {
        // ...
    }
}

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

javapublic class Student {
    private String name;
    private double gpa;
    private int year;
    
    // Constructor 1: เฉพาะชื่อ
    public Student(String name) {
        this.name = name;
        this.gpa = 0.0;      // default
        this.year = 1;       // default
    }
    
    // Constructor 2: ชื่อ + gpa
    public Student(String name, double gpa) {
        this.name = name;
        this.gpa = gpa;
        this.year = 1;       // default
    }
    
    // Constructor 3: ทั้งหมด
    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 ไหน
        
        Student s1 = new Student("John");
        s1.displayInfo();  // Name: John | GPA: 0.00 | Year: 1
        
        Student s2 = new Student("Jane", 3.75);
        s2.displayInfo();  // Name: Jane | GPA: 3.75 | Year: 1
        
        Student s3 = new Student("Bob", 3.50, 2);
        s3.displayInfo();  // Name: Bob | GPA: 3.50 | Year: 2
    }
}

ปัญหาของ Overloading แบบซ้ำซ้อน

❌ Code ซ้ำซ้อน

java// ❌ ไม่ดี: Code ซ้ำกัน
public class Student {
    private String name;
    private double gpa;
    private int year;
    
    public Student(String name) {
        this.name = name;
        this.gpa = 0.0;      // ← ซ้ำ
        this.year = 1;       // ← ซ้ำ
    }
    
    public Student(String name, double gpa) {
        this.name = name;    // ← ซ้ำ
        this.gpa = gpa;
        this.year = 1;       // ← ซ้ำ
    }
    
    public Student(String name, double gpa, int year) {
        this.name = name;    // ← ซ้ำ
        this.gpa = gpa;      // ← ซ้ำ
        this.year = year;
    }
}

ปัญหา:

  • ❌ Code ซ้ำซ้อน
  • ❌ ถ้าแก้ validation → ต้องแก้ทุก constructor
  • ❌ Maintainability ต่ำ

Constructor Chaining คืออะไร?

Constructor Chaining = Constructor เรียก Constructor อื่น เพื่อ reuse code

textConstructor Chaining ใช้:
- this(...) → เรียก constructor อื่นใน class เดียวกัน
- ต้องอยู่บรรทัดแรก

Chaining: Syntax

javapublic class ClassName {
    // Constructor 1
    public ClassName(Type1 param1) {
        this(param1, defaultValue2);  // ← เรียก Constructor 2
    }
    
    // Constructor 2
    public ClassName(Type1 param1, Type2 param2) {
        this(param1, param2, defaultValue3);  // ← เรียก Constructor 3
    }
    
    // Constructor 3 - master constructor
    public ClassName(Type1 param1, Type2 param2, Type3 param3) {
        // initialize ทั้งหมดที่นี่
        this.field1 = param1;
        this.field2 = param2;
        this.field3 = param3;
    }
}

ตัวอย่างที่ 2: Constructor Chaining

javapublic class Student {
    private String name;
    private double gpa;
    private int year;
    
    // Constructor 1: เฉพาะชื่อ
    public Student(String name) {
        this(name, 0.0);     // ← เรียก Constructor 2
    }
    
    // Constructor 2: ชื่อ + gpa
    public Student(String name, double gpa) {
        this(name, gpa, 1);  // ← เรียก Constructor 3
    }
    
    // Constructor 3: Master constructor
    public Student(String name, double gpa, int year) {
        // ✓ Initialize ทั้งหมดที่นี่เท่านั้น
        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) {
        Student s1 = new Student("John");
        s1.displayInfo();  // Name: John | GPA: 0.00 | Year: 1
        
        Student s2 = new Student("Jane", 3.75);
        s2.displayInfo();  // Name: Jane | GPA: 3.75 | Year: 1
        
        Student s3 = new Student("Bob", 3.50, 2);
        s3.displayInfo();  // Name: Bob | GPA: 3.50 | Year: 2
    }
}

ข้อดี:

  • ✓ Code ไม่ซ้ำ
  • ✓ Maintain ง่าย
  • ✓ Validation อยู่ที่เดียว

ตัวอย่างที่ 3: Chaining ด้วย Validation

javapublic class BankAccount {
    private String accountNumber;
    private String accountHolder;
    private double balance;
    
    // Constructor 1: บัญชีใหม่ (balance = 0)
    public BankAccount(String accountNumber, String accountHolder) {
        this(accountNumber, accountHolder, 0);  // ← เรียก master
    }
    
    // Constructor 2: Master constructor (มี validation)
    public BankAccount(String accountNumber, String accountHolder, double initialBalance) {
        // Validation
        if (accountNumber == null || accountNumber.isEmpty()) {
            throw new IllegalArgumentException("Account number required");
        }
        if (accountHolder == null || accountHolder.isEmpty()) {
            throw new IllegalArgumentException("Account holder required");
        }
        if (initialBalance < 0) {
            throw new IllegalArgumentException("Balance cannot be negative");
        }
        
        // Initialize
        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) {
        // ✓ สร้างบัญชีใหม่ (balance = 0)
        BankAccount acc1 = new BankAccount("ACC001", "John Doe");
        acc1.displayInfo();
        
        // ✓ สร้างบัญชีที่มี initial deposit
        BankAccount acc2 = new BankAccount("ACC002", "Jane Smith", 50000);
        acc2.displayInfo();
        
        // ❌ Validation ทำงาน
        try {
            BankAccount invalid = new BankAccount("", "Bob");
        } catch (IllegalArgumentException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Output:

textAccount: ACC001 | Holder: John Doe | Balance: 0.00
Account: ACC002 | Holder: Jane Smith | Balance: 50000.00
Error: Account number required

ตัวอย่างที่ 4: Overloading ด้วย Different Types

javapublic class Product {
    private String productID;
    private String productName;
    private double price;
    private String category;
    
    // Constructor 1: ข้อมูลพื้นฐาน
    public Product(String id, String name, double price) {
        this(id, name, price, "Uncategorized");  // ← เรียก master
    }
    
    // Constructor 2: Master constructor
    public Product(String id, String name, double price, String category) {
        if (id == null || id.isEmpty()) {
            throw new IllegalArgumentException("Product ID required");
        }
        if (price < 0) {
            throw new IllegalArgumentException("Price cannot be negative");
        }
        
        this.productID = id;
        this.productName = name;
        this.price = price;
        this.category = category;
    }
    
    public void displayInfo() {
        System.out.printf("ID: %s | Name: %s | Price: %.2f | Category: %s\n",
                         productID, productName, price, category);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        Product p1 = new Product("P001", "Laptop", 25000);
        p1.displayInfo();  // Category: Uncategorized
        
        Product p2 = new Product("P002", "Mouse", 500, "Electronics");
        p2.displayInfo();  // Category: Electronics
    }
}

Chaining Rules

กฎที่ต้องจำ

text1. this(...) ต้องอยู่บรรทัดแรกเสมอ
2. Constructor หนึ่งเรียก Constructor อื่นได้เพียงหนึ่งตัว
3. ห้ามเรียกตัวเองเป็นวงกลม (recursive)

✓ ถูกต้อง

javapublic Student(String name) {
    this(name, 0.0);  // ← บรรทัดแรก ✓
}

public Student(String name, double gpa) {
    this(name, gpa, 1);  // ← บรรทัดแรก ✓
}

❌ ผิด

java// ❌ ผิด: this() ไม่ได้อยู่บรรทัดแรก
public Student(String name) {
    System.out.println("Creating student");
    this(name, 0.0);  // ← ERROR!
}

// ❌ ผิด: เรียก constructor 2 ตัว
public Student(String name) {
    this(name, 0.0);
    this(name, 0.0, 1);  // ← ERROR!
}

// ❌ ผิด: เรียกตัวเองเป็นวงกลม
public Student(String name) {
    this(name);  // ← ERROR! Infinite loop
}

ตัวอย่างที่ 5: Complex Chaining

javapublic class Employee {
    private String employeeID;
    private String name;
    private String department;
    private double salary;
    private int startYear;
    
    // Constructor 1: ข้อมูลพื้นฐาน
    public Employee(String id, String name) {
        this(id, name, "General");  // ← เรียก Constructor 2
    }
    
    // Constructor 2: พื้นฐาน + department
    public Employee(String id, String name, String department) {
        this(id, name, department, 30000);  // ← เรียก Constructor 3
    }
    
    // Constructor 3: พื้นฐาน + department + salary
    public Employee(String id, String name, String department, double salary) {
        this(id, name, department, salary, 2025);  // ← เรียก Constructor 4
    }
    
    // Constructor 4: Master constructor
    public Employee(String id, String name, String department, double salary, int startYear) {
        // 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 (startYear < 2000 || startYear > 2025) {
            throw new IllegalArgumentException("Invalid start year");
        }
        
        // Initialize
        this.employeeID = id;
        this.name = name;
        this.department = department;
        this.salary = salary;
        this.startYear = startYear;
        
        System.out.println("✓ Employee created: " + name);
    }
    
    public void displayInfo() {
        System.out.printf("ID: %s | Name: %s | Dept: %s | Salary: %.2f | Year: %d\n",
                         employeeID, name, department, salary, startYear);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        System.out.println("=== Constructor 1 ===");
        Employee e1 = new Employee("E001", "John");
        e1.displayInfo();
        
        System.out.println("\n=== Constructor 2 ===");
        Employee e2 = new Employee("E002", "Jane", "Engineering");
        e2.displayInfo();
        
        System.out.println("\n=== Constructor 3 ===");
        Employee e3 = new Employee("E003", "Bob", "Marketing", 45000);
        e3.displayInfo();
        
        System.out.println("\n=== Constructor 4 (Master) ===");
        Employee e4 = new Employee("E004", "Alice", "HR", 50000, 2020);
        e4.displayInfo();
    }
}

Output:

text=== Constructor 1 ===
✓ Employee created: John
ID: E001 | Name: John | Dept: General | Salary: 30000.00 | Year: 2025

=== Constructor 2 ===
✓ Employee created: Jane
ID: E002 | Name: Jane | Dept: Engineering | Salary: 30000.00 | Year: 2025

=== Constructor 3 ===
✓ Employee created: Bob
ID: E003 | Name: Bob | Dept: Marketing | Salary: 45000.00 | Year: 2025

=== Constructor 4 (Master) ===
✓ Employee created: Alice
ID: E004 | Name: Alice | Dept: HR | Salary: 50000.00 | Year: 2020

ตัวอย่างที่ 6: Overloading ด้วย Different Parameter Orders

javapublic class Rectangle {
    private double width;
    private double height;
    private String color;
    
    // Constructor 1: width, height
    public Rectangle(double width, double height) {
        this(width, height, "white");  // ← เรียก master
    }
    
    // Constructor 2: width, height, color
    public Rectangle(double width, double height, String color) {
        if (width <= 0 || height <= 0) {
            throw new IllegalArgumentException("Dimensions must be positive");
        }
        this.width = width;
        this.height = height;
        this.color = color;
    }
    
    public double getArea() {
        return width * height;
    }
    
    public void displayInfo() {
        System.out.printf("Rectangle: %.1f x %.1f | Color: %s | Area: %.2f\n",
                         width, height, color, getArea());
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        Rectangle r1 = new Rectangle(10, 5);
        r1.displayInfo();  // Rectangle: 10.0 x 5.0 | Color: white | Area: 50.00
        
        Rectangle r2 = new Rectangle(8, 4, "blue");
        r2.displayInfo();  // Rectangle: 8.0 x 4.0 | Color: blue | Area: 32.00
    }
}

Best Practices: Overloading & Chaining

1. Master Constructor Pattern

java// ✓ ดี: มี master constructor หนึ่งตัว
public class Student {
    // Constructors อื่นเรียก master
    public Student(String name) {
        this(name, 0.0, 1);
    }
    
    public Student(String name, double gpa) {
        this(name, gpa, 1);
    }
    
    // Master constructor - มี validation/initialization ทั้งหมด
    public Student(String name, double gpa, int year) {
        // validation
        // initialization
    }
}

// ❌ ไม่ดี: ไม่มี master, code ซ้ำ
public class Student {
    public Student(String name) {
        // validation + initialization
    }
    
    public Student(String name, double gpa) {
        // validation + initialization (ซ้ำ)
    }
}

2. เรียงลำดับจาก Simple → Complex

java// ✓ ดี: เรียงจาก simple → complex
public class Product {
    // Simple
    public Product(String id, String name) {
        this(id, name, 0.0);
    }
    
    // Medium
    public Product(String id, String name, double price) {
        this(id, name, price, "Uncategorized");
    }
    
    // Complex (Master)
    public Product(String id, String name, double price, String category) {
        // ...
    }
}

3. Default Values ที่เหมาะสม

java// ✓ ดี: Default values มีความหมาย
public class Account {
    public Account(String id) {
        this(id, 0.0);        // balance = 0 (reasonable)
    }
    
    public Account(String id, double balance) {
        // ...
    }
}

// ❌ ไม่ดี: Default values ไม่เหมาะ
public class Account {
    public Account(String id) {
        this(id, -999);       // balance = -999 (unreasonable)
    }
}

4. Clear Parameter Names

java// ✓ ดี: Parameter names ชัดเจน
public class Employee {
    public Employee(String employeeID, String fullName) {
        this(employeeID, fullName, "General");
    }
    
    public Employee(String employeeID, String fullName, String departmentName) {
        // ...
    }
}

// ⚠️ สับสน: Parameter names คล้ายกัน
public class Employee {
    public Employee(String id, String name) {
        this(id, name, "General");
    }
    
    public Employee(String id, String name, String dept) {
        // id = employeeID หรือ departmentID?
    }
}

ตัวอย่างสุดท้าย: Real-World Scenario

javapublic class ShoppingCart {
    private String cartID;
    private String customerID;
    private List<String> items;
    private double discount;
    private long createdTime;
    
    // Constructor 1: Basic (new customer)
    public ShoppingCart(String customerID) {
        this(generateCartID(), customerID);
    }
    
    // Constructor 2: With cartID
    public ShoppingCart(String cartID, String customerID) {
        this(cartID, customerID, 0);
    }
    
    // Constructor 3: With discount
    public ShoppingCart(String cartID, String customerID, double discount) {
        // Validation
        if (cartID == null || cartID.isEmpty()) {
            throw new IllegalArgumentException("Cart ID required");
        }
        if (customerID == null || customerID.isEmpty()) {
            throw new IllegalArgumentException("Customer ID required");
        }
        if (discount < 0 || discount > 100) {
            throw new IllegalArgumentException("Discount must be 0-100");
        }
        
        // Initialize
        this.cartID = cartID;
        this.customerID = customerID;
        this.items = new ArrayList<>();
        this.discount = discount;
        this.createdTime = System.currentTimeMillis();
        
        System.out.printf("✓ Cart created: %s for customer %s\n", cartID, customerID);
    }
    
    private static String generateCartID() {
        return "CART" + System.currentTimeMillis();
    }
    
    public void addItem(String item) {
        items.add(item);
        System.out.println("✓ Added: " + item);
    }
    
    public void displayInfo() {
        System.out.printf("Cart: %s | Customer: %s | Items: %d | Discount: %.1f%%\n",
                         cartID, customerID, items.size(), discount);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        System.out.println("=== New Customer (Auto Cart ID) ===");
        ShoppingCart cart1 = new ShoppingCart("CUST001");
        cart1.addItem("Laptop");
        cart1.addItem("Mouse");
        cart1.displayInfo();
        
        System.out.println("\n=== Existing Cart ===");
        ShoppingCart cart2 = new ShoppingCart("CART123", "CUST002");
        cart2.addItem("Keyboard");
        cart2.displayInfo();
        
        System.out.println("\n=== VIP Customer (with discount) ===");
        ShoppingCart cart3 = new ShoppingCart("CART456", "CUST003", 10);
        cart3.addItem("Monitor");
        cart3.displayInfo();
    }
}

Output:

text=== New Customer (Auto Cart ID) ===
✓ Cart created: CART1730372400000 for customer CUST001
✓ Added: Laptop
✓ Added: Mouse
Cart: CART1730372400000 | Customer: CUST001 | Items: 2 | Discount: 0.0%

=== Existing Cart ===
✓ Cart created: CART123 for customer CUST002
✓ Added: Keyboard
Cart: CART123 | Customer: CUST002 | Items: 1 | Discount: 0.0%

=== VIP Customer (with discount) ===
✓ Cart created: CART456 for customer CUST003
✓ Added: Monitor
Cart: CART456 | Customer: CUST003 | Items: 1 | Discount: 10.0%

สรุป: Constructor Overloading & Chaining

text┌────────────────────────────────────────────────┐
│  Constructor Overloading & Chaining           │
├────────────────────────────────────────────────┤
│                                                │
│  OVERLOADING (หลาย Constructors)             │
│  ├─ ชื่อเดียวกัน                              │
│  ├─ Parameters ต่างกัน                        │
│  └─ ให้ flexibility ในการสร้าง object        │
│                                                │
│  CHAINING (เรียก Constructor อื่น)           │
│  ├─ ใช้ this(...)                             │
│  ├─ ต้องอยู่บรรทัดแรก                         │
│  └─ Reuse code, ลด duplication               │
│                                                │
│  MASTER CONSTRUCTOR PATTERN                   │
│  ├─ Constructor หนึ่งตัวที่มี logic ทั้งหมด   │
│  ├─ Constructors อื่นเรียก master            │
│  └─ Easy to maintain                          │
│                                                │
│  BEST PRACTICES                               │
│  ├─ เรียงจาก simple → complex                │
│  ├─ Default values ที่เหมาะสม                │
│  ├─ Clear parameter names                     │
│  └─ Validation อยู่ใน master constructor     │
│                                                │
└────────────────────────────────────────────────┘