Đa hình vs Overriding vs Quá tải


347

Về mặt Java, khi ai đó hỏi:

Đa hình là gì?

Sẽ quá tải hoặc ghi đè là một câu trả lời có thể chấp nhận?

Tôi nghĩ rằng có một chút nhiều hơn thế.

NẾU bạn đã có một lớp cơ sở trừu tượng xác định một phương thức không có triển khai và bạn đã định nghĩa phương thức đó trong lớp phụ, đó có còn là quá mức không?

Tôi nghĩ rằng quá tải không phải là câu trả lời đúng cho chắc chắn.


Dưới đây câu trả lời giải thích rất tốt về đa hình. Nhưng tôi phản đối mạnh mẽ khi nói quá tải là một loại đa hình, mà tôi đã cố gắng biện minh trong câu hỏi và câu trả lời của mình rằng thực sự tập trung vào quá tải có phải là đa hình hay không. Tôi đã cố gắng biện minh cho câu trả lời @The Digital Gabeg trong chủ đề này. Tham khảo Xây dựng: Quá tải phương thức là liên kết thời gian tĩnh / biên dịch nhưng không phải là đa hình. Là chính xác để tương quan liên kết tĩnh với đa hình?
PraveenKumar Lalasangi

Câu trả lời:


894

Cách rõ ràng nhất để thể hiện tính đa hình là thông qua một lớp cơ sở trừu tượng (hoặc giao diện)

public abstract class Human{
   ...
   public abstract void goPee();
}

Lớp này là trừu tượng bởi vì goPee() phương thức này không thể xác định được đối với Con người. Nó chỉ có thể xác định cho các lớp con Nam và Nữ. Ngoài ra, Con người là một khái niệm trừu tượng - Bạn không thể tạo ra một con người không phải là Nam cũng không phải Nữ. Nó phải là cái này hay cái khác.

Vì vậy, chúng tôi trì hoãn việc thực hiện bằng cách sử dụng lớp trừu tượng.

public class Male extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Stand Up");
    }
}

public class Female extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Sit Down");
    }
}

Bây giờ chúng ta có thể nói toàn bộ căn phòng đầy Con người đi tiểu.

public static void main(String[] args){
    ArrayList<Human> group = new ArrayList<Human>();
    group.add(new Male());
    group.add(new Female());
    // ... add more...

    // tell the class to take a pee break
    for (Human person : group) person.goPee();
}

Chạy này sẽ mang lại:

Stand Up
Sit Down
...

37
@yuudachi. Tôi đã đưa ra ví dụ này khi dạy một lớp. Lớp "Tài khoản ngân hàng" chuẩn không thực sự thể hiện "tính trừu tượng" của lớp cơ sở. Một ví dụ kinh điển khác (Động vật, gây ồn ào) quá trừu tượng để hiểu. Tôi đang tìm kiếm một cơ sở duy nhất với các lớp con quá rõ ràng. Trên thực tế, goPee () là ví dụ duy nhất tôi nghĩ ra đó không phải là phân biệt giới tính hay rập khuôn. (mặc dù trong lớp, tôi đã in "xuống hội trường bên trái" thay vì đứng lên hoặc ngồi xuống.)
Chris Cudmore

100
Ví dụ này cũng làm nổi bật sự khó khăn của việc sử dụng một hệ thống phân cấp để mô tả các hệ thống sinh học. Một số người, chẳng hạn như trẻ nhỏ, đi tiểu ở hầu hết mọi vị trí - và trẻ sơ sinh không thể dễ dàng được nói với goPee (). Một số người là liên giới tính, trong đó các nhãn sinh học của "nam" hoặc "nữ" trở nên không rõ ràng; ý nghĩa xã hội thậm chí còn phức tạp hơn. Như một ví dụ giảng dạy, nó cho thấy làm thế nào các giả định mô hình hóa có thể có kết quả tiêu cực, chẳng hạn như ngụ ý rằng ai đó (ví dụ, một sinh viên lập trình OO), người không tự nhiên hoặc không liên quan đến nhau không thực sự là con người.
Andrew Dalke

7
Tôi có thể nghĩ về ít nhất một số ít người sẽ bác bỏ luận điểm "bạn không thể tạo ra một con người không phải là nam hay nữ", mặc dù điều đó vẫn đúng với mã của bạn ... sự trừu tượng xấu Tôi cho rằng tôi đang nói ? ;)
Frank W. Zammetti

2
Tôi nghĩ điều quan trọng là chỉ ra rằng đó chỉ là đa hình vì phiên bản goPee () để gọi chỉ có thể được xác định khi chạy. Trong khi ví dụ này ngụ ý rằng, thật tốt khi chỉ ra tại sao chính xác đó là đa hình. Ngoài ra, nó không yêu cầu các lớp anh chị em. Nó có thể là một mối quan hệ cha-con là tốt. Hoặc thậm chí các lớp hoàn toàn không liên quan mà ngẫu nhiên có cùng chức năng. Một ví dụ về điều này có thể là hàm .toString (). Có thể được gọi ngẫu nhiên trên bất kỳ đối tượng nào, nhưng trình biên dịch không bao giờ có thể biết chính xác loại đối tượng nào.
Tor Valamo

20
@AndrewDalke, +1 để ghi chú về độ phức tạp sinh học. Ngoài ra, goPeekhông lấy trường hấp dẫn làm đầu vào. Sự phụ thuộc này vào trạng thái toàn cầu làm cho việc kiểm tra đơn vị trở nên CatheterizedIntersexAstronautkhó khăn và cho thấy rằng phân lớp có thể không phải luôn luôn là phương pháp tốt nhất để cấu thành các tính trạng.
Mike Samuel

99

Đa hình là khả năng của một thể hiện lớp hoạt động như thể nó là một thể hiện của một lớp khác trong cây thừa kế của nó, thường là một trong các lớp tổ tiên của nó. Ví dụ, trong Java tất cả các lớp kế thừa từ Object. Do đó, bạn có thể tạo một biến kiểu Object và gán cho nó một thể hiện của bất kỳ lớp nào.

An ghi đèlà một loại hàm xuất hiện trong một lớp kế thừa từ một lớp khác. Hàm ghi đè "thay thế" một hàm được kế thừa từ lớp cơ sở, nhưng thực hiện theo cách mà nó được gọi ngay cả khi một thể hiện của lớp của nó đang giả vờ là một loại khác thông qua đa hình. Tham khảo ví dụ trước, bạn có thể định nghĩa lớp của riêng mình và ghi đè hàm toString (). Vì hàm này được kế thừa từ Object, nên nó vẫn sẽ có sẵn nếu bạn sao chép một thể hiện của lớp này vào một biến kiểu Object. Thông thường, nếu bạn gọi toString () trên lớp của mình trong khi nó đang giả vờ là Object, phiên bản của toString sẽ thực sự kích hoạt là phiên bản được xác định trên chính Object. Tuy nhiên, vì hàm là ghi đè, nên định nghĩa của toString () từ lớp của bạn được sử dụng ngay cả khi thể hiện của lớp '

Quá tải là hành động xác định nhiều phương thức có cùng tên, nhưng với các tham số khác nhau. Nó không liên quan đến ghi đè hoặc đa hình.


8
Điều này đã cũ nhưng Đa hình không ngụ ý rằng lớp khác phải ở trong cây thừa kế. Nó thực hiện trong Java nếu bạn coi các giao diện là một phần của cây thừa kế, nhưng không phải trong Go, nơi các giao diện được triển khai ngầm.
JN

5
Trên thực tế, bạn không cần các lớp cho đa hình.
StCredZero

3
Tôi là người mới và sửa tôi nếu tôi sai, nhưng tôi sẽ không nói quá tải không liên quan đến đa hình. Ít nhất là trong Java, tính đa hình là khi việc triển khai được chọn dựa trên loại người gọi và quá tải là khi việc triển khai được chọn dựa trên loại tham số, phải không? Nhìn thấy sự tương đồng giữa hai người giúp tôi hiểu nó.
csjacobs24

9
Sai. Ad hoc polymorphismlà những gì bạn mô tả trong phần Quá tải của bạn và một trường hợp đa hình.
Jossie Calderon

1
"Nó không liên quan đến ghi đè hoặc đa hình". Phát biểu này là sai.
Shailesh Pratapwar

45

Đa hình có nghĩa là nhiều hơn một hình thức, cùng một đối tượng thực hiện các hoạt động khác nhau theo yêu cầu.

Đa hình có thể đạt được bằng cách sử dụng hai cách, đó là

  1. Phương pháp ghi đè
  2. Phương thức quá tải

Phương thức quá tải phương thức có nghĩa là viết hai hoặc nhiều phương thức trong cùng một lớp bằng cách sử dụng cùng tên phương thức, nhưng các tham số truyền là khác nhau.

Ghi đè phương thức có nghĩa là chúng ta sử dụng các tên phương thức trong các lớp khác nhau, điều đó có nghĩa là phương thức lớp cha được sử dụng trong lớp con.

Trong Java để đạt được tính đa hình, một biến tham chiếu siêu lớp có thể chứa đối tượng lớp phụ.

Để đạt được tính đa hình, mọi nhà phát triển phải sử dụng cùng tên phương thức trong dự án.


4
+1 cho câu trả lời hay. Câu trả lời được chấp nhận chỉ giải thích một loại đa hình. Câu trả lời này đã hoàn tất.
apadana

1
đa hình là một mô hình (OOP), nhưng ghi đè & quá tải là các phương tiện ngôn ngữ.
曾 其

Đa hình cũng có thể đạt được bằng loại chung.
Minh Nghĩa

43

Đây là một ví dụ về đa hình trong pseudo-C # / Java:

class Animal
{
    abstract string MakeNoise ();
}

class Cat : Animal {
    string MakeNoise () {
        return "Meow";
    }
}

class Dog : Animal {
    string MakeNoise () {
        return "Bark";
    }
}

Main () {
   Animal animal = Zoo.GetAnimal ();
   Console.WriteLine (animal.MakeNoise ());
}

Hàm Main không biết loại động vật và phụ thuộc vào hành vi cụ thể của phương thức MakeNaty ().

Chỉnh sửa: Có vẻ như Brian đánh tôi đến cú đấm. Buồn cười chúng tôi đã sử dụng ví dụ tương tự. Nhưng đoạn mã trên sẽ giúp làm rõ các khái niệm.


Đó là một ví dụ về đa hình thời gian chạy. Đa hình thời gian biên dịch cũng có thể thông qua quá tải phương thức và các kiểu chung.
Pete Kirkham

Hình dạng -> Hình bình hành -> Hình chữ nhật -> Hình vuông
mpen

@ yankee2905 trong trường hợp này, tôi nghĩ bạn có thể sử dụng các giao diện, vì một lớp có thể thực hiện nhiều giao diện.
Sam003

1
@Zhisheng Hoặc thêm một phương thức pee trong lớp cha trừu tượng? Tôi sẽ sử dụng giao diện để thực hiện một cái gì đó khác.
joey rohan 8/8/2015

42

Cả ghi đè và quá tải đều được sử dụng để đạt được tính đa hình.

Bạn có thể có một phương thức trong một lớp bị ghi đè trong một hoặc nhiều lớp con. Phương thức này thực hiện những thứ khác nhau tùy thuộc vào lớp nào được sử dụng để khởi tạo một đối tượng.

    abstract class Beverage {
       boolean isAcceptableTemperature();
    }

    class Coffee extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature > 70;
       }
    }

    class Wine extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature < 10;
       }
    }

Bạn cũng có thể có một phương thức bị quá tải với hai hoặc nhiều bộ đối số. Phương thức thực hiện những điều khác nhau dựa trên loại (các) đối số được thông qua.

    class Server {
        public void pour (Coffee liquid) {
            new Cup().fillToTopWith(liquid);
        }

        public void pour (Wine liquid) {
            new WineGlass().fillHalfwayWith(liquid);
        }

        public void pour (Lemonade liquid, boolean ice) {
            Glass glass = new Glass();
            if (ice) {
                glass.fillToTopWith(new Ice());
            }
            glass.fillToTopWith(liquid);
        }
    }

Tôi cho rằng nó đã được bỏ phiếu vì quá tải phương pháp trong lịch sử không được coi là một phần của đa hình trong mô hình hướng đối tượng. Quá tải phương thức và đa hình là hai tính năng độc lập, độc lập của ngôn ngữ lập trình.
Sergio Acosta

7
Như tôi đã nói trong câu trả lời của mình ở đây, tôi không đồng ý - hai tính năng này không trực giao, nhưng có liên quan chặt chẽ với nhau. Đa hình! = Kế thừa. Bạn có phiếu bầu của tôi.
Peter Meyer

2
Nói cách khác, loại đa hình so với đa hình ad-hoc. Tôi ủng hộ câu trả lời này, ngay cả khi không đầy đủ như vậy, bởi vì nó nói chính xác rằng cả quá tải và ghi đè đều liên quan đến đa hình. Nói rằng tính đa hình trong các ngôn ngữ OOP chỉ có thể đạt được bằng sự kế thừa lớp đơn giản là sai - chúng ta nên nhớ rằng có một số ngôn ngữ OOP khác ngoài Java và C ++, trong đó người ta có thể sử dụng các khái niệm như gửi đi, đa hình ad hoc, đa hình tham số, v.v. .
rsenna

2
@rsenna Điều này có thể không đầy đủ nhưng nó trả lời câu hỏi tốt hơn nhiều so với IMHO còn lại. Ngoài ra, rất tốt đẹp khi bạn đề cập đến đa hình ad-hoc và tham số.
Valentin Radu

15

Bạn đúng rằng quá tải không phải là câu trả lời.

Không phải là ghi đè. Ghi đè là phương tiện mà bạn có được đa hình. Đa hình là khả năng cho một đối tượng thay đổi hành vi dựa trên loại của nó. Điều này được thể hiện tốt nhất khi người gọi của một đối tượng thể hiện tính đa hình không biết loại đối tượng cụ thể là gì.


3
Nó không phải là hành vi của đối tượng thay đổi, nhưng thực hiện của mình. Cùng một hành vi, thực hiện khác nhau, đó là đa hình.
QBziZ

@QBziZ Bạn cần xác định hành vi , đặc biệt là tính từ giống nhau . Nếu hành vi là như nhau, tại sao thực hiện của họ phải khác nhau? Không phải là ai đó không hài lòng với một triển khai nhất định, do đó đòi hỏi một cách khác.
Sнаđошƒаӽ

11

Cụ thể nói quá tải hoặc ghi đè không cung cấp cho hình ảnh đầy đủ. Đa hình đơn giản là khả năng của một đối tượng để chuyên môn hóa hành vi của nó dựa trên loại của nó.

Tôi không đồng ý với một số câu trả lời ở đây vì quá tải là một dạng đa hình (đa hình tham số) trong trường hợp một phương thức có cùng tên có thể hành xử khác nhau cho các loại tham số khác nhau. Một ví dụ điển hình là quá tải toán tử. Bạn có thể định nghĩa "+" để chấp nhận các loại tham số khác nhau - giả sử chuỗi hoặc int - và dựa trên các loại đó, "+" sẽ hoạt động khác nhau.

Đa hình cũng bao gồm các phương thức kế thừa và ghi đè, mặc dù chúng có thể là trừu tượng hoặc ảo trong loại cơ sở. Về mặt đa hình dựa trên kế thừa, Java chỉ hỗ trợ kế thừa lớp duy nhất giới hạn hành vi đa hình của nó đối với một chuỗi các kiểu cơ sở duy nhất. Java hỗ trợ thực hiện nhiều giao diện, một dạng hành vi đa hình khác.


Bạn nói đúng về ý nghĩa của những từ liên quan, nhưng trong ngữ cảnh lập trình, khi mọi người nói "đa hình", chúng luôn có nghĩa là "đa hình dựa trên thừa kế". Điểm thú vị, nhưng tôi nghĩ rằng việc mô tả đa hình theo cách này sẽ khiến mọi người nhầm lẫn.
Gabeg kỹ thuật số

Có thể dễ dàng hơn để giải thích tính đa hình về mặt thừa kế, nhưng cách mà câu hỏi đặc biệt này được hỏi tôi nghĩ rằng cũng rất thận trọng khi mô tả đa hình tham số.
Patrick McElhaney

4
Để rõ ràng, tôi nghĩ các hình thức khác nhau nên được nêu - điều mà tôi thậm chí chưa thực hiện đầy đủ - bởi vì có một vài câu trả lời ở đây được trình bày là tuyệt đối. Tôi tôn trọng không đồng ý rằng trong "bối cảnh lập trình viên ..." đa hình "luôn có nghĩa là" đa hình dựa trên thừa kế ""
Peter Meyer

2
Tôi nghĩ rằng quá tải được phân loại tốt hơn là Ad-hoc_polymorphism en.wikipedia.org/wiki/iêu
Manu

Tôi có xu hướng đồng ý với 'The Digital Gabeg' sau đây. Nếu bạn đang thảo luận về OOP, đa hình thường có nghĩa là đa hình phụ, và nếu bạn đang thảo luận về lý thuyết loại, nó có nghĩa là bất kỳ loại đa hình nào. Nhưng như bạn nói, với 'bối cảnh lập trình viên' thì quá mơ hồ để chế giễu.
Manu

7

Đa hình đơn giản có nghĩa là "Nhiều hình thức".

Nó không YÊU CẦU kế thừa để đạt được ... như việc thực hiện giao diện, hoàn toàn không phải là kế thừa, phục vụ các nhu cầu đa hình. Có thể cho rằng, việc thực hiện giao diện phục vụ nhu cầu đa hình "Tốt hơn" kế thừa.

Ví dụ, bạn sẽ tạo ra một siêu hạng để mô tả tất cả những thứ có thể bay? Tôi nên nghĩ là không. Bạn sẽ được phục vụ tốt nhất để tạo ra một giao diện mô tả chuyến bay và để nó ở đó.

Vì vậy, vì các giao diện mô tả hành vi và tên phương thức mô tả hành vi (đối với lập trình viên), không quá xa để xem xét quá tải phương thức như một dạng đa hình ít hơn.


2
Chắc chắn là câu trả lời tốt nhất chưa. Đa hình có thể được áp dụng cho tất cả các cấu trúc ngôn ngữ, có thể là danh từ (lớp) hoặc động từ (phương thức).
Radu Gasler

6

Ví dụ kinh điển, Chó và mèo là động vật, động vật có phương pháp makeNaty. Tôi có thể lặp đi lặp lại thông qua một loạt các động vật gọi makeNaty trên chúng và hy vọng rằng chúng sẽ thực hiện ở đó.

Mã gọi không phải biết chúng là động vật cụ thể nào.

Đó là những gì tôi nghĩ về đa hình.


4

Đa hình là khả năng cho một đối tượng xuất hiện dưới nhiều hình thức. Điều này liên quan đến việc sử dụng tính kế thừa và các hàm ảo để xây dựng một họ các đối tượng có thể thay thế cho nhau. Lớp cơ sở chứa các nguyên mẫu của các hàm ảo, có thể chưa được thực hiện hoặc với các cài đặt mặc định khi ứng dụng ra lệnh và các lớp dẫn xuất khác nhau, mỗi lớp thực hiện chúng khác nhau để ảnh hưởng đến các hành vi khác nhau.


4

Cũng không:

Quá tải là khi bạn có cùng tên hàm nhận các tham số khác nhau.

Ghi đè là khi một lớp con thay thế phương thức của cha mẹ bằng một phương thức của chính nó (điều này trong bản thân nó không cấu thành đa hình).

Đa hình là liên kết muộn, ví dụ, các phương thức lớp cơ sở (cha mẹ) đang được gọi nhưng cho đến khi bộ thực thi biết ứng dụng thực sự là gì - nó có thể là một lớp con có các phương thức khác nhau. Điều này là do bất kỳ lớp con nào cũng có thể được sử dụng khi lớp cơ sở được xác định.

Trong Java, bạn thấy tính đa hình rất nhiều với thư viện bộ sưu tập:

int countStuff(List stuff) {
  return stuff.size();
}

Danh sách là lớp cơ sở, trình biên dịch không có đầu mối nếu bạn đang đếm một danh sách được liên kết, vectơ, mảng hoặc triển khai danh sách tùy chỉnh, miễn là nó hoạt động như một Danh sách:

List myStuff = new MyTotallyAwesomeList();
int result = countStuff(myStuff);

Nếu bạn đang quá tải, bạn có:

int countStuff(LinkedList stuff) {...}
int countStuff(ArrayList stuff) {...}
int countStuff(MyTotallyAwesomeList stuff) {...}
etc...

và phiên bản chính xác của CountStuff () sẽ được trình biên dịch chọn để khớp với các tham số.


4

Mặc dù, Đa hình đã được giải thích rất chi tiết trong bài viết này nhưng tôi muốn nhấn mạnh hơn vào lý do tại sao một phần của nó.

Tại sao đa hình rất quan trọng trong bất kỳ ngôn ngữ OOP nào.

Chúng ta hãy thử xây dựng một ứng dụng đơn giản cho TV có và không có Kế thừa / Đa hình. Đăng từng phiên bản của ứng dụng, chúng tôi làm một hồi tưởng nhỏ.

Giả sử, bạn là một kỹ sư phần mềm tại một công ty TV và bạn được yêu cầu viết phần mềm cho bộ điều khiển Âm lượng, Độ sáng và Màu sắc để tăng và giảm giá trị của chúng theo lệnh người dùng.

Bạn bắt đầu với các lớp viết cho mỗi tính năng này bằng cách thêm

  1. set: - Để đặt giá trị của bộ điều khiển. (Giả sử điều này có mã cụ thể của bộ điều khiển)
  2. get: - Để lấy giá trị của bộ điều khiển. (Giả sử điều này có mã cụ thể của bộ điều khiển)
  3. điều chỉnh: - Để xác thực đầu vào và đặt bộ điều khiển. (Xác thực chung .. độc lập với bộ điều khiển)
  4. ánh xạ đầu vào của người dùng với các bộ điều khiển: - Để có được đầu vào của người dùng và gọi các bộ điều khiển phù hợp.

Phiên bản ứng dụng 1

import java.util.Scanner;    
class VolumeControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV1    {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

/*
 *       There can be n number of controllers
 * */
public class TvApplicationV1 {
    public static void main(String[] args)  {
        VolumeControllerV1 volumeControllerV1 = new VolumeControllerV1();
        BrightnessControllerV1 brightnessControllerV1 = new BrightnessControllerV1();
        ColourControllerV1 colourControllerV1 = new ColourControllerV1();


        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println("Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV1.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV1.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV1.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV1.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV1.adjust(5);
                    break;
                }
                case 6: {
                colourControllerV1.adjust(-5);
                break;
            }
            default:
                System.out.println("Shutting down...........");
                break OUTER;
        }

    }
    }
}

Bây giờ bạn đã có phiên bản đầu tiên của ứng dụng làm việc của chúng tôi sẵn sàng để được triển khai. Thời gian để phân tích công việc được thực hiện cho đến nay.

Các sự cố trong Ứng dụng TV Phiên bản 1

  1. Mã điều chỉnh (int value) được nhân đôi trong cả ba lớp. Bạn muốn giảm thiểu sự trùng lặp mã. (Nhưng bạn đã không nghĩ về mã phổ biến và chuyển nó sang một số siêu hạng để tránh mã trùng lặp)

Bạn quyết định sống với điều đó miễn là ứng dụng của bạn hoạt động như mong đợi.

Sau đó, ông chủ của bạn quay lại với bạn và yêu cầu bạn thêm chức năng đặt lại vào ứng dụng hiện có. Đặt lại sẽ đặt cả 3 ba bộ điều khiển về giá trị mặc định tương ứng của chúng.

Bạn bắt đầu viết một lớp mới (ResetFunctionV2) cho chức năng mới và ánh xạ mã ánh xạ đầu vào của người dùng cho tính năng mới này.

Phiên bản ứng dụng 2

import java.util.Scanner;
class VolumeControllerV2    {

    private int defaultValue = 25;
    private int value;

    int getDefaultValue() {
        return defaultValue;
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV2   {

    private int defaultValue = 50;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV2    {

    private int defaultValue = 40;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class ResetFunctionV2 {

    private VolumeControllerV2 volumeControllerV2 ;
    private BrightnessControllerV2 brightnessControllerV2;
    private ColourControllerV2 colourControllerV2;

    ResetFunctionV2(VolumeControllerV2 volumeControllerV2, BrightnessControllerV2 brightnessControllerV2, ColourControllerV2 colourControllerV2)  {
        this.volumeControllerV2 = volumeControllerV2;
        this.brightnessControllerV2 = brightnessControllerV2;
        this.colourControllerV2 = colourControllerV2;
    }
    void onReset()    {
        volumeControllerV2.set(volumeControllerV2.getDefaultValue());
        brightnessControllerV2.set(brightnessControllerV2.getDefaultValue());
        colourControllerV2.set(colourControllerV2.getDefaultValue());
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV2 {
    public static void main(String[] args)  {
        VolumeControllerV2 volumeControllerV2 = new VolumeControllerV2();
        BrightnessControllerV2 brightnessControllerV2 = new BrightnessControllerV2();
        ColourControllerV2 colourControllerV2 = new ColourControllerV2();

        ResetFunctionV2 resetFunctionV2 = new ResetFunctionV2(volumeControllerV2, brightnessControllerV2, colourControllerV2);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV2.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV2.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV2.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV2.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV2.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV2.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV2.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Vậy là bạn đã sẵn sàng cho ứng dụng của mình với tính năng Reset. Nhưng, bây giờ bạn bắt đầu nhận ra rằng

Các sự cố trong Ứng dụng TV Phiên bản 2

  1. Nếu bộ điều khiển mới được giới thiệu cho sản phẩm, bạn phải thay đổi mã tính năng Đặt lại.
  2. Nếu số lượng bộ điều khiển tăng rất cao, bạn sẽ gặp vấn đề trong việc giữ các tham chiếu của bộ điều khiển.
  3. Đặt lại mã tính năng được kết hợp chặt chẽ với tất cả mã của Bộ điều khiển (để lấy và đặt giá trị mặc định).
  4. Đặt lại lớp tính năng (ResetFunctionV2) có thể truy cập phương thức khác của lớp Điều khiển (điều chỉnh) không mong muốn.

Đồng thời, bạn nghe được từ ông chủ của mình rằng bạn có thể phải thêm một tính năng trong đó mỗi bộ điều khiển, khi khởi động, cần kiểm tra phiên bản trình điều khiển mới nhất từ ​​kho lưu trữ trình điều khiển được lưu trữ của công ty qua internet.

Bây giờ bạn bắt đầu nghĩ rằng tính năng mới này sẽ được thêm giống với tính năng Đặt lại và Vấn đề về Ứng dụng (V2) sẽ được nhân lên nếu bạn không tính lại ứng dụng của mình.

Bạn bắt đầu nghĩ đến việc sử dụng tính kế thừa để bạn có thể tận dụng khả năng đa hình của JAVA và bạn thêm một lớp trừu tượng mới (ControllerV3) vào

  1. Khai báo chữ ký của phương thức get và set.
  2. Chứa điều chỉnh phương thức thực hiện đã được sao chép trước đó trong số tất cả các bộ điều khiển.
  3. Khai báo phương thức setDefault để tính năng đặt lại có thể dễ dàng thực hiện bằng cách sử dụng Đa hình.

Với những cải tiến này, bạn đã có sẵn phiên bản 3 của ứng dụng TV.

Phiên bản ứng dụng 3

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

abstract class ControllerV3 {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
    abstract void setDefault();
}
class VolumeControllerV3 extends ControllerV3   {

    private int defaultValue = 25;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
}
class  BrightnessControllerV3  extends ControllerV3   {

    private int defaultValue = 50;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
}
class ColourControllerV3 extends ControllerV3   {

    private int defaultValue = 40;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
}

class ResetFunctionV3 {

    private List<ControllerV3> controllers = null;

    ResetFunctionV3(List<ControllerV3> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (ControllerV3 controllerV3 :this.controllers)  {
            controllerV3.setDefault();
        }
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV3 {
    public static void main(String[] args)  {
        VolumeControllerV3 volumeControllerV3 = new VolumeControllerV3();
        BrightnessControllerV3 brightnessControllerV3 = new BrightnessControllerV3();
        ColourControllerV3 colourControllerV3 = new ColourControllerV3();

        List<ControllerV3> controllerV3s = new ArrayList<>();
        controllerV3s.add(volumeControllerV3);
        controllerV3s.add(brightnessControllerV3);
        controllerV3s.add(colourControllerV3);

        ResetFunctionV3 resetFunctionV3 = new ResetFunctionV3(controllerV3s);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV3.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV3.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV3.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV3.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV3.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV3.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV3.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Mặc dù hầu hết các vấn đề được liệt kê trong danh sách vấn đề của V2 đã được giải quyết ngoại trừ

Các sự cố trong Ứng dụng TV Phiên bản 3

  1. Đặt lại lớp tính năng (ResetFunctionV3) có thể truy cập phương thức khác của lớp Điều khiển (điều chỉnh) không mong muốn.

Một lần nữa, bạn nghĩ đến việc giải quyết vấn đề này, vì bây giờ bạn có một tính năng khác (cập nhật trình điều khiển khi khởi động) để thực hiện. Nếu bạn không sửa nó, nó cũng sẽ được nhân rộng sang các tính năng mới.

Vì vậy, bạn chia hợp đồng được xác định trong lớp trừu tượng và viết 2 giao diện cho

  1. Đặt lại tính năng.
  2. Cập nhật trình điều khiển.

Và có lớp bê tông đầu tiên của bạn thực hiện chúng như dưới đây

Phiên bản ứng dụng 4

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

interface OnReset {
    void setDefault();
}
interface OnStart {
    void checkForDriverUpdate();
}
abstract class ControllerV4 implements OnReset,OnStart {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class VolumeControllerV4 extends ControllerV4 {

    private int defaultValue = 25;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for VolumeController .... Done");
    }
}
class  BrightnessControllerV4 extends ControllerV4 {

    private int defaultValue = 50;
    private int value;
    @Override
    int get()    {
        return value;
    }
    @Override
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }

    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for BrightnessController .... Done");
    }
}
class ColourControllerV4 extends ControllerV4 {

    private int defaultValue = 40;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for ColourController .... Done");
    }
}
class ResetFunctionV4 {

    private List<OnReset> controllers = null;

    ResetFunctionV4(List<OnReset> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (OnReset onreset :this.controllers)  {
            onreset.setDefault();
        }
    }
}
class InitializeDeviceV4 {

    private List<OnStart> controllers = null;

    InitializeDeviceV4(List<OnStart> controllers)  {
        this.controllers = controllers;
    }
    void initialize()    {
        for (OnStart onStart :this.controllers)  {
            onStart.checkForDriverUpdate();
        }
    }
}
/*
*       so on
*       There can be n number of controllers
*
* */
public class TvApplicationV4 {
    public static void main(String[] args)  {
        VolumeControllerV4 volumeControllerV4 = new VolumeControllerV4();
        BrightnessControllerV4 brightnessControllerV4 = new BrightnessControllerV4();
        ColourControllerV4 colourControllerV4 = new ColourControllerV4();
        List<ControllerV4> controllerV4s = new ArrayList<>();
        controllerV4s.add(brightnessControllerV4);
        controllerV4s.add(volumeControllerV4);
        controllerV4s.add(colourControllerV4);

        List<OnStart> controllersToInitialize = new ArrayList<>();
        controllersToInitialize.addAll(controllerV4s);
        InitializeDeviceV4 initializeDeviceV4 = new InitializeDeviceV4(controllersToInitialize);
        initializeDeviceV4.initialize();

        List<OnReset> controllersToReset = new ArrayList<>();
        controllersToReset.addAll(controllerV4s);
        ResetFunctionV4 resetFunctionV4 = new ResetFunctionV4(controllersToReset);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV4.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV4.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV4.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV4.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV4.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV4.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV4.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Bây giờ tất cả các vấn đề mà bạn phải đối mặt đã được giải quyết và bạn nhận ra rằng với việc sử dụng Kế thừa và Đa hình, bạn có thể

  1. Giữ các phần khác nhau của ứng dụng được ghép lỏng lẻo (Các thành phần tính năng Đặt lại hoặc Cập nhật Trình điều khiển không cần phải biết về các lớp trình điều khiển thực tế (Âm lượng, Độ sáng và Màu sắc), mọi lớp triển khai OnReset hoặc OnStart đều được chấp nhận để tính năng Đặt lại hoặc Cập nhật trình điều khiển thành phần tương ứng).
  2. Việc cải tiến ứng dụng trở nên dễ dàng hơn (Bổ sung bộ điều khiển mới sẽ không ảnh hưởng đến việc thiết lập lại thành phần tính năng cập nhật trình điều khiển và giờ đây thật dễ dàng để bạn thêm những cái mới)
  3. Giữ lớp trừu tượng. (Bây giờ tính năng Đặt lại chỉ có thể thấy phương thức setDefault của bộ điều khiển và tính năng Đặt lại chỉ có thể thấy phương thức bộ điều khiển checkForDriverUpdate)

Hi vọng điêu nay co ich :-)


3

Thuật ngữ quá tải có nghĩa là có nhiều phiên bản của một cái gì đó có cùng tên, thường là các phương thức với các danh sách tham số khác nhau

public int DoSomething(int objectId) { ... }
public int DoSomething(string objectName) { ... }

Vì vậy, các chức năng này có thể làm điều tương tự nhưng bạn có tùy chọn để gọi nó bằng ID hoặc tên. Không có gì để làm với thừa kế, các lớp trừu tượng, vv

Ghi đè thường đề cập đến đa hình, như bạn đã mô tả trong câu hỏi của mình


2

quá tải là khi bạn định nghĩa 2 phương thức có cùng tên nhưng tham số khác nhau

ghi đè là nơi bạn thay đổi hành vi của lớp cơ sở thông qua một hàm có cùng tên trong một lớp con.

Vì vậy, Đa hình có liên quan đến ghi đè nhưng không thực sự quá tải.

Tuy nhiên nếu ai đó cho tôi một câu trả lời đơn giản là "ghi đè" cho câu hỏi "Đa hình là gì?" Tôi sẽ yêu cầu giải thích thêm.


2

ghi đè giống như ẩn một phương thức được kế thừa bằng cách khai báo một phương thức có cùng tên và chữ ký với phương thức cấp trên (siêu phương thức), điều này thêm một hành vi đa hình cho lớp. nói cách khác, quyết định chọn phương thức cấp độ sẽ được gọi sẽ được đưa ra vào thời gian chạy chứ không phải vào thời gian biên dịch. điều này dẫn đến khái niệm về giao diện và thực hiện.


2

Đa hình là gì?

Từ hướng dẫn java

Định nghĩa từ điển của đa hình đề cập đến một nguyên tắc trong sinh học, trong đó một sinh vật hoặc loài có thể có nhiều hình thức hoặc giai đoạn khác nhau. Nguyên tắc này cũng có thể được áp dụng cho lập trình hướng đối tượng và các ngôn ngữ như ngôn ngữ Java. Các lớp con của một lớp có thể định nghĩa các hành vi độc đáo của riêng chúng và chia sẻ một số chức năng tương tự của lớp cha.

Bằng cách xem xét các ví dụ và định nghĩa, ghi đè nên được chấp nhận câu trả lời.

Về truy vấn thứ hai của bạn:

NẾU bạn đã có một lớp cơ sở trừu tượng xác định một phương thức không có triển khai và bạn đã định nghĩa phương thức đó trong lớp phụ, đó có còn là quá mức không?

Nó nên được gọi là ghi đè.

Hãy xem ví dụ này để hiểu các kiểu ghi đè khác nhau.

  1. Lớp cơ sở không cung cấp triển khai và lớp con phải ghi đè phương thức hoàn chỉnh - (trừu tượng)
  2. Lớp cơ sở cung cấp triển khai mặc định và lớp con có thể thay đổi hành vi
  3. Lớp con thêm phần mở rộng để thực hiện lớp cơ sở bằng cách gọi super.methodName() là câu lệnh đầu tiên
  4. Lớp cơ sở xác định cấu trúc của thuật toán (Phương thức mẫu) và lớp con sẽ ghi đè lên một phần của thuật toán

đoạn mã:

import java.util.HashMap;

abstract class Game implements Runnable{

    protected boolean runGame = true;
    protected Player player1 = null;
    protected Player player2 = null;
    protected Player currentPlayer = null;

    public Game(){
        player1 = new Player("Player 1");
        player2 = new Player("Player 2");
        currentPlayer = player1;
        initializeGame();
    }

    /* Type 1: Let subclass define own implementation. Base class defines abstract method to force
        sub-classes to define implementation    
    */

    protected abstract void initializeGame();

    /* Type 2: Sub-class can change the behaviour. If not, base class behaviour is applicable */
    protected void logTimeBetweenMoves(Player player){
        System.out.println("Base class: Move Duration: player.PlayerActTime - player.MoveShownTime");
    }

    /* Type 3: Base class provides implementation. Sub-class can enhance base class implementation by calling
        super.methodName() in first line of the child class method and specific implementation later */
    protected void logGameStatistics(){
        System.out.println("Base class: logGameStatistics:");
    }
    /* Type 4: Template method: Structure of base class can't be changed but sub-class can some part of behaviour */
    protected void runGame() throws Exception{
        System.out.println("Base class: Defining the flow for Game:");  
        while ( runGame) {
            /*
            1. Set current player
            2. Get Player Move
            */
            validatePlayerMove(currentPlayer);  
            logTimeBetweenMoves(currentPlayer);
            Thread.sleep(500);
            setNextPlayer();
        }
        logGameStatistics();
    }
    /* sub-part of the template method, which define child class behaviour */
    protected abstract void validatePlayerMove(Player p);

    protected void setRunGame(boolean status){
        this.runGame = status;
    }
    public void setCurrentPlayer(Player p){
        this.currentPlayer = p;
    }
    public void setNextPlayer(){
        if ( currentPlayer == player1) {
            currentPlayer = player2;
        }else{
            currentPlayer = player1;
        }
    }
    public void run(){
        try{
            runGame();
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

class Player{
    String name;
    Player(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
}

/* Concrete Game implementation  */
class Chess extends Game{
    public Chess(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized Chess game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate Chess move:"+p.getName());
    }
    protected void logGameStatistics(){
        super.logGameStatistics();
        System.out.println("Child class: Add Chess specific logGameStatistics:");
    }
}
class TicTacToe extends Game{
    public TicTacToe(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized TicTacToe game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate TicTacToe move:"+p.getName());
    }
}

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

            Game game = new Chess();
            Thread t1 = new Thread(game);
            t1.start();
            Thread.sleep(1000);
            game.setRunGame(false);
            Thread.sleep(1000);

            game = new TicTacToe();
            Thread t2 = new Thread(game);
            t2.start();
            Thread.sleep(1000);
            game.setRunGame(false);

        }catch(Exception err){
            err.printStackTrace();
        }       
    }
}

đầu ra:

Child class: Initialized Chess game
Base class: Defining the flow for Game:
Child class: Validate Chess move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate Chess move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Child class: Add Chess specific logGameStatistics:
Child class: Initialized TicTacToe game
Base class: Defining the flow for Game:
Child class: Validate TicTacToe move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate TicTacToe move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:

2

Tôi nghĩ rằng các bạn đang trộn lẫn các khái niệm. Đa hình là khả năng của một đối tượng hành xử khác nhau trong thời gian chạy. Để đạt được điều này, bạn cần hai điều kiện cần thiết:

  1. Ràng buộc muộn
  2. Di sản.

Đã nói rằng quá tải có nghĩa là một cái gì đó khác nhau để ghi đè tùy thuộc vào ngôn ngữ bạn đang sử dụng. Ví dụ trong Java không tồn tại ghi đè nhưng quá tải . Các phương thức quá tải với chữ ký khác nhau cho lớp cơ sở của nó có sẵn trong lớp con. Nếu không họ sẽ bị ghi đè (xin vui lòng, xem ý tôi là bây giờ thực tế không có cách nào để gọi phương thức lớp cơ sở của bạn từ bên ngoài đối tượng).

Tuy nhiên trong C ++ thì không như vậy. Bất kỳ phương thức quá tải nào, độc lập cho dù chữ ký có giống nhau hay không (số lượng khác nhau, loại khác nhau) cũng sẽ bị ghi đè . Đó là ngày nay, phương thức của lớp cơ sở không còn có sẵn trong lớp con khi được gọi từ bên ngoài đối tượng lớp con, rõ ràng.

Vì vậy, câu trả lời là khi nói về việc sử dụng Java quá tải . Trong bất kỳ ngôn ngữ nào khác có thể khác nhau như nó xảy ra trong c ++


1

Tính đa hình có nhiều khả năng liên quan đến ý nghĩa của nó ... đối với QUÁ TRÌNH trong java

Đó là tất cả về hành vi khác nhau của đối tượng CÙNG trong các tình huống khác nhau (Theo cách lập trình ... bạn có thể gọi các ARGUMENT khác nhau)

Tôi nghĩ rằng ví dụ dưới đây sẽ giúp bạn hiểu ... Mặc dù đó không phải là mã java PURE ...

     public void See(Friend)
     {
        System.out.println("Talk");
     }

Nhưng nếu chúng ta thay đổi ARGUMENT ... BEHAVIOR sẽ bị thay đổi ...

     public void See(Enemy)
     {
        System.out.println("Run");
     }

Người (ở đây là "Đối tượng") giống ...


1

Đa hình là một triển khai nhiều đối tượng hoặc bạn có thể nói nhiều dạng của một đối tượng. giả sử bạn có lớp Animalslà lớp cơ sở trừu tượng và nó có một phương thức gọi là movement()định nghĩa cách con vật di chuyển. Bây giờ trong thực tế chúng ta có các loại động vật khác nhau và chúng di chuyển khác nhau, một số trong số chúng có 2 chân, một số khác có 4 và không có chân, vv .. Để xác định khác nhau movement()của mỗi loài động vật trên trái đất, chúng ta cần áp dụng đa hình. Tuy nhiên, bạn cần định nghĩa nhiều lớp hơn là lớp, Dogs Cats Fishv.v. Sau đó, bạn cần mở rộng các lớp đó khỏi lớp cơ sở Animalsvà ghi đè phương thức của nómovement() bằng chức năng di chuyển mới dựa trên mỗi con vật bạn có. Bạn cũng có thể dùngInterfacesđể đạt được điều đó. Từ khóa ở đây là ghi đè, quá tải là khác nhau và không được coi là đa hình. với quá tải, bạn có thể định nghĩa nhiều phương thức "có cùng tên" nhưng với các tham số khác nhau trên cùng một đối tượng hoặc lớp.


0

Đa hình liên quan đến khả năng của một ngôn ngữ có đối tượng khác nhau được xử lý thống nhất bằng cách sử dụng một giao diện duy nhất; như vậy nó có liên quan đến việc ghi đè, vì vậy giao diện (hoặc lớp cơ sở) là đa hình, người thực hiện là đối tượng ghi đè (hai mặt của cùng một huy chương)

Dù sao, sự khác biệt giữa hai thuật ngữ được giải thích tốt hơn bằng các ngôn ngữ khác, chẳng hạn như c ++: một đối tượng đa hình trong c ++ hoạt động như đối tác java nếu hàm cơ sở là ảo, nhưng nếu phương thức không ảo thì bước nhảy mã được giải quyết tĩnh , và loại thực không được kiểm tra trong thời gian chạy vì vậy, tính đa hình bao gồm khả năng cho một đối tượng hành xử khác nhau tùy thuộc vào giao diện được sử dụng để truy cập nó; hãy để tôi làm một ví dụ trong mã giả:

class animal {
    public void makeRumor(){
        print("thump");
    }
}
class dog extends animal {
    public void makeRumor(){
        print("woff");
    }
}

animal a = new dog();
dog b = new dog();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

(giả sử makeRumor KHÔNG phải là ảo)

java không thực sự cung cấp mức độ đa hình này (còn gọi là cắt đối tượng).

động vật a = chó mới (); chó b = chó mới ();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

trên cả hai trường hợp, nó sẽ chỉ in woff .. vì a và b đang tham chiếu đến lớp chó



động vật a = chó mới (); a được xây dựng như một con chó, và sẽ in "woff". Nếu bạn muốn nó in thump thì bạn cần upcast nó. ((Động vật) a) .makeRumor ()
Chris Cudmore

Đó là tham chiếu u ám, nhưng đối tượng vẫn là một con chó. Nếu bạn muốn nó là một con vật, bạn phải làm rõ đối tượng.
Chris Cudmore

Tìm ra. Câu hỏi đã được gắn thẻ Java. Bạn đã trả lời C ++. Bạn có thể đúng trong C ++. Tôi chắc chắn đúng trong Java.
Chris Cudmore

nên xảy ra mỗi khi một nhà xây dựng sao chép có liên quan ở đây là một tham chiếu fredoaurus.com/notes-cpp/oop-condesturationors / trường hợp ba trận đấu; bỏ qua toán tử mới chỉ có để định hướng tạo.
Lorenzo Boccaccia

0
import java.io.IOException;

class Super {

    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName() + " - I'm parent");
        return null;
    }

}

class SubOne extends Super {

    @Override
    protected Super getClassName(Super s)  {
        System.out.println(this.getClass().getSimpleName() + " - I'm Perfect Overriding");
        return null;
    }

}

class SubTwo extends Super {

    @Override
    protected Super getClassName(Super s) throws NullPointerException {
        System.out.println(this.getClass().getSimpleName() + " - I'm Overriding and Throwing Runtime Exception");
        return null;
    }

}

class SubThree extends Super {

    @Override
    protected SubThree getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Returning SubClass Type");
        return null;
    }

}

class SubFour extends Super {

    @Override
    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Throwing Narrower Exception ");
        return null;
    }

}

class SubFive extends Super {

    @Override
    public Super getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and have broader Access ");
        return null;
    }

}

class SubSix extends Super {

    public Super getClassName(Super s, String ol) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading ");
        return null;
    }

}

class SubSeven extends Super {

    public Super getClassName(SubSeven s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading because Method signature (Argument) changed.");
        return null;
    }

}

public class Test{

    public static void main(String[] args) throws Exception {

        System.out.println("Overriding\n");

        Super s1 = new SubOne(); s1.getClassName(null);

        Super s2 = new SubTwo(); s2.getClassName(null);

        Super s3 = new SubThree(); s3.getClassName(null);

        Super s4 = new SubFour(); s4.getClassName(null);

        Super s5 = new SubFive(); s5.getClassName(null);

        System.out.println("Overloading\n");

        SubSix s6 = new SubSix(); s6.getClassName(null, null);

        s6 = new SubSix(); s6.getClassName(null);

        SubSeven s7 = new SubSeven(); s7.getClassName(s7);

        s7 = new SubSeven(); s7.getClassName(new Super());

    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.