บทนำ: ปัญหาของ 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 เดียว
- Constructor Overloading คืออะไร?
- Overloading: Syntax
- ตัวอย่างที่ 1: Constructor Overloading พื้นฐาน
- ปัญหาของ Overloading แบบซ้ำซ้อน
- ❌ Code ซ้ำซ้อน
- Constructor Chaining คืออะไร?
- Chaining: Syntax
- ตัวอย่างที่ 2: Constructor Chaining
- ตัวอย่างที่ 3: Chaining ด้วย Validation
- ตัวอย่างที่ 4: Overloading ด้วย Different Types
- Chaining Rules
- กฎที่ต้องจำ
- ✓ ถูกต้อง
- ❌ ผิด
- ตัวอย่างที่ 5: Complex Chaining
- ตัวอย่างที่ 6: Overloading ด้วย Different Parameter Orders
- Best Practices: Overloading & Chaining
- 1. Master Constructor Pattern
- 2. เรียงลำดับจาก Simple → Complex
- 3. Default Values ที่เหมาะสม
- 4. Clear Parameter Names
- ตัวอย่างสุดท้าย: Real-World Scenario
- สรุป: Constructor Overloading & Chaining
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 │
│ │
└────────────────────────────────────────────────┘
