การสืบทอดคุณสมบัติ

บทนำ: ปัญหาของการทำซ้ำ Code

เมื่อเราเขียนโปรแกรม บ่อยครั้งที่เรามี classes ที่คล้ายกัน และ มี code ที่ซ้ำกัน

java// ❌ ปัญหา: Code ซ้ำซ้อน
public class Student {
    private String name;
    private String email;
    private String studentID;
    
    public Student(String name, String email, String studentID) {
        this.name = name;
        this.email = email;
        this.studentID = studentID;
    }
    
    public void displayInfo() {
        System.out.printf("Name: %s | Email: %s\n", name, email);
    }
}

public class Teacher {
    private String name;
    private String email;
    private String teacherID;
    
    public Teacher(String name, String email, String teacherID) {
        this.name = name;
        this.email = email;
        this.teacherID = teacherID;
    }
    
    public void displayInfo() {
        System.out.printf("Name: %s | Email: %s\n", name, email);
    }
}

ปัญหา:

  • ❌ nameemail ซ้ำกัน
  • ❌ Constructor logic ซ้ำกัน
  • ❌ displayInfo() เกือบเหมือนกัน
  • ❌ ถ้าแก้ bug → ต้องแก้ทั้ง class!

Inheritance คืออะไร?

Inheritance (สืบทอด) = Class หนึ่งสามารถ “สืบทอด” (inherit) properties และ methods จาก class อื่น

textConcept:
┌──────────────────────┐
│   Person (Parent)    │
│ ─────────────────    │
│ - name               │
│ - email              │
│ + displayInfo()      │
└──────────────────────┘
        △
        │ (สืบทอด)
        │
    ┌───┴────┐
    │        │
┌─────────┐ ┌────────┐
│ Student │ │ Teacher│
│ (Child) │ │ (Child)│
└─────────┘ └────────┘

Inheritance Syntax

การประกาศ

java// Syntax:
public class ChildClass extends ParentClass {
    // Child-specific code
}

// ตัวอย่าง:
public class Student extends Person {
    // Student inherits from Person
}

public class Teacher extends Person {
    // Teacher inherits from Person
}

ตัวอย่างที่ 1: Simple Inheritance

มาเขียน code ที่ใช้การสืบทอด เพื่อหลีกเลี่ยงการทำซ้ำ

java// Parent Class
public class Person {
    private String name;
    private String email;
    
    public Person(String name, String email) {
        this.name = name;
        this.email = email;
    }
    
    public String getName() {
        return this.name;
    }
    
    public String getEmail() {
        return this.email;
    }
    
    public void displayInfo() {
        System.out.printf("Name: %s | Email: %s\n", name, email);
    }
}

// Child Class 1
public class Student extends Person {
    private String studentID;
    
    public Student(String name, String email, String studentID) {
        super(name, email);  // ← เรียก parent constructor
        this.studentID = studentID;
    }
    
    public String getStudentID() {
        return this.studentID;
    }
}

// Child Class 2
public class Teacher extends Person {
    private String teacherID;
    private String department;
    
    public Teacher(String name, String email, String teacherID, String dept) {
        super(name, email);  // ← เรียก parent constructor
        this.teacherID = teacherID;
        this.department = dept;
    }
    
    public String getTeacherID() {
        return this.teacherID;
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        Student student = new Student("John", "[email protected]", "S001");
        student.displayInfo();  // ← ใช้ method จาก Person
        System.out.println("ID: " + student.getStudentID());
        
        Teacher teacher = new Teacher("Dr. Smith", "[email protected]", "T001", "CS");
        teacher.displayInfo();  // ← ใช้ method จาก Person
        System.out.println("ID: " + teacher.getTeacherID());
    }
}

Output:

textName: John | Email: [email protected]
ID: S001
Name: Dr. Smith | Email: [email protected]
ID: T001

คำอธิบาย:

  • Student และ Teacher สืบทอดจาก Person
  • ทั้ง 2 class สามารถใช้ displayInfo() ของ Person ได้
  • super(name, email) เรียก parent constructor เพื่อ initialize name และ email
  • Code ไม่ซ้ำซ้อน! ✓

What Gets Inherited?

สิ่งที่สืบทอดได้

text✓ สืบทอดได้:
  ├─ public methods
  ├─ public attributes (ไม่ดี practice)
  ├─ protected methods
  └─ protected attributes

❌ สืบทอดไม่ได้:
  ├─ private methods
  ├─ private attributes
  ├─ Constructor (แต่ต้องเรียก super)
  └─ static methods (เข้าถึงได้แต่ไม่ override)

ตัวอย่างที่ 2: Inheritance ด้วย Protected

มาเขียน code ที่ใช้ protected เพื่อให้ child class เข้าถึงได้

javapublic class Animal {
    protected String name;          // ← protected (accessible in child)
    private String color;           // ← private (not accessible)
    
    public Animal(String name, String color) {
        this.name = name;           // ✓ Can access own private
        this.color = color;
    }
    
    protected void makeSound() {    // ← protected
        System.out.println("Some sound");
    }
    
    public void display() {
        System.out.println("Name: " + name);
        System.out.println("Color: " + color);
    }
}

public class Dog extends Animal {
    private String breed;
    
    public Dog(String name, String color, String breed) {
        super(name, color);
        this.breed = breed;
    }
    
    @Override
    protected void makeSound() {
        System.out.println("Woof! Woof!");
    }
    
    public void dogsInfo() {
        // ✓ Can access protected name from parent
        System.out.println("Dog: " + name);
        
        // ❌ Cannot access private color from parent
        // System.out.println("Color: " + color);  // ERROR!
        
        System.out.println("Breed: " + breed);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Buddy", "Brown", "Golden Retriever");
        
        dog.display();          // From Animal class
        dog.dogsInfo();         // From Dog class
        dog.makeSound();        // Overridden method
    }
}

Output:

textName: Buddy
Color: Brown
Dog: Buddy
Breed: Golden Retriever
Woof! Woof!

คำอธิบาย:

  • protected members สามารถเข้าถึงได้จาก child class
  • private members ไม่สามารถเข้าถึงได้จาก child class
  • makeSound() ถูก override (เปลี่ยนพฤติกรรม) ใน Dog class

Constructor Chaining ใน Inheritance

ทำไมต้อง super()?

เมื่อ child object ถูกสร้าง parent constructor ต้องถูกเรียก เพื่อ initialize parent’s fields

javapublic class Vehicle {
    private String brand;
    private int year;
    
    public Vehicle(String brand, int year) {
        this.brand = brand;
        this.year = year;
        System.out.println("Vehicle constructor called");
    }
}

public class Car extends Vehicle {
    private String color;
    
    public Car(String brand, int year, String color) {
        super(brand, year);      // ← ต้องเรียก parent constructor
        this.color = color;
        System.out.println("Car constructor called");
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        Car car = new Car("Toyota", 2024, "Red");
    }
}

Output:

textVehicle constructor called
Car constructor called

คำอธิบาย:

  • super(brand, year) เรียก parent constructor ก่อน
  • จากนั้น child constructor ทำงาน
  • ลำดับ: Parent initialization → Child initialization

ตัวอย่างที่ 3: Multi-level Inheritance

Inheritance สามารถ “ต่อเนื่อง” ได้หลายระดับ

java// Level 1: Grandparent
public class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void eat() {
        System.out.println(name + " is eating");
    }
}

// Level 2: Parent
public class Mammal extends Animal {
    protected String furColor;
    
    public Mammal(String name, String furColor) {
        super(name);
        this.furColor = furColor;
    }
    
    public void sleep() {
        System.out.println(name + " is sleeping");
    }
}

// Level 3: Child
public class Dog extends Mammal {
    private String breed;
    
    public Dog(String name, String furColor, String breed) {
        super(name, furColor);
        this.breed = breed;
    }
    
    public void bark() {
        System.out.println(name + " says: Woof!");
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Rex", "Black", "Husky");
        
        // สามารถใช้ method จาก ทั้ง Animal, Mammal, Dog
        dog.eat();      // From Animal
        dog.sleep();    // From Mammal
        dog.bark();     // From Dog
    }
}

Output:

textRex is eating
Rex is sleeping
Rex says: Woof!

คำอธิบาย:

  • Dog → Mammal → Animal (hierarchy)
  • Dog สามารถใช้ method ทั้ง 3 levels ได้
  • Constructor chain: Dog → Mammal → Animal

ตัวอย่างที่ 4: Inheritance ด้วย Business Logic

เขียน code ที่สมจริง

java// Parent Class
public class Employee {
    private String employeeID;
    private String name;
    private double salary;
    
    public Employee(String id, String name, double salary) {
        this.employeeID = id;
        this.name = name;
        this.salary = salary;
    }
    
    public String getName() {
        return this.name;
    }
    
    public double getSalary() {
        return this.salary;
    }
    
    public void displayInfo() {
        System.out.printf("ID: %s | Name: %s | Salary: %.2f\n",
                         employeeID, name, salary);
    }
    
    public double calculateBonus() {
        return salary * 0.05;  // 5% bonus
    }
}

// Child Class 1: Manager
public class Manager extends Employee {
    private int teamSize;
    
    public Manager(String id, String name, double salary, int teamSize) {
        super(id, name, salary);
        this.teamSize = teamSize;
    }
    
    @Override
    public double calculateBonus() {
        return getSalary() * 0.10;  // 10% bonus
    }
    
    public void displayInfo() {
        super.displayInfo();
        System.out.println("Team Size: " + teamSize);
    }
}

// Child Class 2: Developer
public class Developer extends Employee {
    private String programmingLanguage;
    
    public Developer(String id, String name, double salary, String language) {
        super(id, name, salary);
        this.programmingLanguage = language;
    }
    
    @Override
    public double calculateBonus() {
        return getSalary() * 0.08;  // 8% bonus
    }
    
    public void displayInfo() {
        super.displayInfo();
        System.out.println("Language: " + programmingLanguage);
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        Employee emp = new Employee("E001", "John", 50000);
        Manager mgr = new Manager("M001", "Alice", 80000, 5);
        Developer dev = new Developer("D001", "Bob", 60000, "Java");
        
        System.out.println("=== Employee ===");
        emp.displayInfo();
        System.out.println("Bonus: " + emp.calculateBonus() + "\n");
        
        System.out.println("=== Manager ===");
        mgr.displayInfo();
        System.out.println("Bonus: " + mgr.calculateBonus() + "\n");
        
        System.out.println("=== Developer ===");
        dev.displayInfo();
        System.out.println("Bonus: " + dev.calculateBonus());
    }
}

Output:

text=== Employee ===
ID: E001 | Name: John | Salary: 50000.00
Bonus: 2500.0

=== Manager ===
ID: M001 | Name: Alice | Salary: 80000.00
Team Size: 5
Bonus: 8000.0

=== Developer ===
ID: D001 | Name: Bob | Salary: 60000.00
Language: Java
Bonus: 4800.0

คำอธิบาย:

  • Manager และ Developer สืบทอด Employee
  • calculateBonus() ถูก override (เปลี่ยน logic) ใน child classes
  • ทุก class มี displayInfo() แต่ Manager และ Developer แสดง info เพิ่มเติม

IS-A Relationship

Inheritance ใช้เมื่อมี “IS-A” ความสัมพันธ์

text✓ ถูกต้อง (IS-A):
  ├─ Dog IS-A Animal
  ├─ Student IS-A Person
  └─ Manager IS-A Employee

❌ ผิด (HAS-A):
  ├─ Car HAS-A Engine (ไม่ควรใช้ inheritance)
  ├─ Person HAS-A Phone
  └─ Employee HAS-A Office

ตัวอย่างที่ 5: IS-A vs HAS-A

java// ✓ IS-A: ใช้ Inheritance
public class SportsCar extends Car {
    private int maxSpeed;
    
    public SportsCar(String brand, int year, String color, int maxSpeed) {
        super(brand, year, color);
        this.maxSpeed = maxSpeed;
    }
}

// ✓ HAS-A: ใช้ Composition (ไม่ใช่ inheritance)
public class Car {
    private Engine engine;  // ← Car HAS-A Engine
    
    public Car(Engine engine) {
        this.engine = engine;
    }
}

public class Engine {
    private String type;
    
    public Engine(String type) {
        this.type = type;
    }
}

// ใช้งาน
public class Main {
    public static void main(String[] args) {
        // SportsCar IS-A Car
        SportsCar ferrari = new SportsCar("Ferrari", 2024, "Red", 340);
        
        // Car HAS-A Engine
        Engine engine = new Engine("V8");
        Car car = new Car(engine);
    }
}

Benefits ของ Inheritance

Inheritance ให้ประโยชน์หลักๆ ดังนี้:

1. Code Reusability (ใช้ code ซ้ำ)

  • ไม่ต้องเขียน code เดียวกันหลายครั้ง
  • Parent methods ใช้ได้ใน child classes

2. Logical Hierarchy (ลำดับชั้นตรรกะ)

  • ช่วยจัดระบบ code ให้ชัดเจน
  • สะท้อนความสัมพันธ์ของ objects

3. Maintainability (ง่ายต่อการดูแล)

  • แก้ bug ใน parent → child ทั้งหมด fix
  • Reduce duplication

4. Extensibility (ขยายความสามารถ)

  • เพิ่ม functionality ใน child ได้อย่างง่าย
  • Parent ยังใช้ได้ตามปกติ

Best Practices: Inheritance

1. ใช้ Inheritance สำหรับ IS-A เท่านั้น

java// ✓ ถูกต้อง
public class Circle extends Shape {
    // Circle IS-A Shape
}

// ❌ ผิด
public class Car extends Garage {
    // Car doesn't IS-A Garage (should HAS-A)
}

2. ไม่ควร Extend มากเกินไป

java// ⚠️ Too deep hierarchy
A → B → C → D → E → F

// ✓ ดีกว่า
A → B
A → C

3. ใช้ super() เพื่อเรียก Parent Constructor

java// ✓ ดี
public class Student extends Person {
    public Student(String name) {
        super(name);  // Call parent constructor
    }
}

// ❌ ไม่ดี
public class Student extends Person {
    public Student(String name) {
        // Forgot to call super()
    }
}

4. Protected > Public สำหรับ Internal Data

java// ✓ ดี
public class Parent {
    protected String data;  // Only child can access
}

// ❌ ไม่ดี
public class Parent {
    public String data;  // Anyone can access/modify
}

สรุป

การสืบทอดคุณสมบัติ (Inheritance) เป็นหนึ่งในแนวคิดหลักของ Object-Oriented Programming ที่ช่วยให้เราเขียน code ที่ ไม่ซ้ำซ้อน และ ติดตามได้ง่าย

ผ่านการใช้ inheritance เราสามารถสร้าง hierarchy ของ classes ที่แสดงความสัมพันธ์ IS-A ระหว่าง objects ได้ชัดเจน เช่น “Dog IS-A Animal” หรือ “Manager IS-A Employee” ด้วยวิธีนี้ child class สามารถ สืบทอด (inherit) methods และ attributes จาก parent class ได้ และสามารถ เพิ่มเติม หรือ ปรับแต่ง functionality ของตัวเอง

สิ่งสำคัญที่ต้องจำคือ inheritance ควรใช้เฉพาะเมื่อมี ความสัมพันธ์ IS-A ที่แท้จริง เท่านั้น และต้องระวังมิให้ hierarchy ลึกเกินไป ซึ่งจะทำให้ code ซับซ้อน เมื่อเข้าใจหลักการพื้นฐานแล้ว คุณจะพบว่า inheritance เป็นเครื่องมือที่ทรงพลัง ในการออกแบบโปรแกรมที่มีประสิทธิภาพและยืดหยุ่น