Bài tập về tính kế thừa trong java năm 2024

Giả sử rằng chúng ta có một lớp

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

1(côn trùng tiếng Anh) Lớp này chứa hai phương thức: 1.

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

2(từ tiếng Anh di chuyển) và 2.

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

3(từ tiếng Anh tấn công)

class Insect {
  private int size;
  private String color;
  public Insect(int size, String color) {
    this.size = size;
    this.color = color;
  }
  public int getSize() {
    return size;
  }
  public void setSize(int size) {
    this.size = size;
  }
  public String getColor() {
    return color;
  }
  public void setColor(String color) {
    this.color = color;
  }
  public void move() {
    System.out.println("Move");
  }
  public void attack() {
    move(); //assuming an insect needs to move before attacking
    System.out.println("Attack");
  }
}

Bây giờ bạn muốn định nghĩa một lớp

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

4(con ong tiếng Anh), là một trong các loại

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

1, nhưng có cách triển khai khác nhau

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

3và

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

2. Điều này có thể được thực hiện bằng cách sử dụng tính kế thừa:

Bài tập về tính kế thừa trong java năm 2024
class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}
public class InheritanceVSComposition {
  public static void main(String[] args) {
    Insect i = new Bee(1, "red");
    i.attack();
  }
}

Sơ đồ phân cấp lớp khá đơn giản:

Bài tập về tính kế thừa trong java năm 2024
Kết quả thực hiện:
Fly
Fly
Attack

"Fly" được gõ hai lần nên phương thức này

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

2được gọi hai lần. Nhưng nó chỉ nên được gọi một lần. Vấn đề là do

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

9. Phương thức này

public class InheritanceVSComposition {
  public static void main(String[] args) {
    Insect i = new Bee(1, "red");
    i.attack();
  }
}

0gọi một phương thức

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

2lớp

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

1. Khi một lớp con gọi

public class InheritanceVSComposition {
  public static void main(String[] args) {
    Insect i = new Bee(1, "red");
    i.attack();
  }
}

3, nó cũng gọi phương thức được ghi đè

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

2. Để khắc phục sự cố chúng ta có thể:

  1. Loại bỏ

    class Bee extends Insect { public Bee(int size, String color) {

    super(size, color);  
    
    } public void move() {
    System.out.println("Fly");  
    
    } public void attack() {
    move();  
    super.attack();  
    
    } }

    3phương thức lớp con. Điều này sẽ làm cho lớp con phụ thuộc vào

    class Bee extends Insect { public Bee(int size, String color) {

    super(size, color);  
    
    } public void move() {
    System.out.println("Fly");  
    
    } public void attack() {
    move();  
    super.attack();  
    
    } }

    3việc triển khai phương thức của lớp cha. Nếu

    public class InheritanceVSComposition { public static void main(String[] args) {

    Insect i = new Bee(1, "red");  
    i.attack();  
    
    } }

    7siêu lớp bắt đầu sử dụng một phương thức di chuyển khác thì lớp con cũng sẽ cần phải thay đổi. Đây là sự đóng gói xấu.
  2. Viết lại phương thức

    class Bee extends Insect { public Bee(int size, String color) {

    super(size, color);  
    
    } public void move() {
    System.out.println("Fly");  
    
    } public void attack() {
    move();  
    super.attack();  
    
    } }

    3như sau:

    public void attack() { move(); System.out.println("Attack"); }

  3. Điều này đảm bảo kết quả chính xác vì lớp con không còn phụ thuộc vào lớp cha nữa. Tuy nhiên, mã này là bản sao của siêu lớp. (phương thức này

    class Bee extends Insect { public Bee(int size, String color) {

    super(size, color);  
    
    } public void move() {
    System.out.println("Fly");  
    
    } public void attack() {
    move();  
    super.attack();  
    
    } }

    3thực hiện những việc phức tạp hơn là chỉ xuất ra một chuỗi). Đây không phải là thiết kế phần mềm tốt và không nên có mã trùng lặp.

Thiết kế kế thừa này không tốt vì lớp con phụ thuộc vào chi tiết triển khai của siêu lớp của nó. Nếu lớp cha thay đổi, lớp con sẽ không hoạt động chính xác.

2. Thành phần

Bạn có thể sử dụng thành phần thay vì kế thừa. Hãy xem xét một giải pháp sử dụng nó. Chức năng này

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

3được trừu tượng hóa như một giao diện.

interface Attack {
  public void move();
  public void attack();
}

Các kiểu tấn công khác nhau có thể được xác định bằng cách triển khai giao diện Tấn công.

class AttackImpl implements Attack {
  private String move;
  private String attack;
  public AttackImpl(String move, String attack) {
    this.move = move;
    this.attack = attack;
  }
  @Override
  public void move() {
    System.out.println(move);
  }
  @Override
  public void attack() {
    move();
    System.out.println(attack);
  }
}

Vì chức năng tấn công là bên ngoài nên lớp

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

1không còn chứa nó nữa.

class Insect {
  private int size;
  private String color;
  public Insect(int size, String color) {
    this.size = size;
    this.color = color;
  }
  public int getSize() {
    return size;
  }
  public void setSize(int size) {
    this.size = size;
  }
  public String getColor() {
    return color;
  }
  public void setColor(String color) {
    this.color = color;
  }
}

Class

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

4(từ English Bee), loại này

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

1có thể tấn công như thế nào.

// This wrapper class wrap an Attack object
class Bee extends Insect implements Attack {
  private Attack attack;
  public Bee(int size, String color, Attack attack) {
    super(size, color);
    this.attack = attack;
  }
  public void move() {
    attack.move();
  }
  public void attack() {
    attack.attack();
  }
}

Sơ đồ lớp:

Bài tập về tính kế thừa trong java năm 2024
public class InheritanceVSComposition2 {
  public static void main(String[] args) {
    Bee a = new Bee(1, "black", new AttackImpl("fly", "move"));
    a.attack();
    // if you need another implementation of move()
    // there is no need to change Insect, we can quickly use new method to attack
    Bee b = new Bee(1, "black", new AttackImpl("fly", "sting"));
    b.attack();
  }
}

Kết quả thực hiện:

class Bee extends Insect {
  public Bee(int size, String color) {
    super(size, color);
  }
  public void move() {
    System.out.println("Fly");
  }
  public void attack() {
    move();
    super.attack();
  }
}

0

3. Khi nào nên sử dụng những phương pháp này?

2 điểm sau đây có thể giúp bạn quyết định giữa kế thừa và thành phần:

  1. Nếu bạn đang xử lý mối quan hệ giữa các lớp có dạng "IS" và một lớp muốn cung cấp tất cả giao diện của nó cho lớp khác thì nên ưu tiên tính kế thừa.
  2. nếu mối quan hệ là "HAS" thì thành phần được ưu tiên hơn.

Vì vậy, tính kế thừa và thành phần có những ứng dụng riêng và cần hiểu rõ giá trị của chúng. Liên kết: