Giao diện so với lớp trừu tượng (chung OO)


1413

Gần đây tôi đã có hai cuộc phỏng vấn qua điện thoại nơi tôi được hỏi về sự khác biệt giữa Giao diện và lớp Trừu tượng. Tôi đã giải thích mọi khía cạnh của chúng mà tôi có thể nghĩ ra, nhưng có vẻ như chúng đang chờ tôi đề cập đến một cái gì đó cụ thể và tôi không biết nó là gì.

Từ kinh nghiệm của tôi, tôi nghĩ rằng những điều sau đây là đúng. Nếu tôi thiếu một điểm chính xin vui lòng cho tôi biết.

Giao diện:

Mỗi Phương thức được khai báo trong Giao diện sẽ phải được triển khai trong lớp con. Chỉ các Sự kiện, Đại biểu, Thuộc tính (C #) và Phương thức mới có thể tồn tại trong Giao diện. Một lớp có thể thực hiện nhiều Giao diện.

Lớp trừu tượng:

Chỉ các phương thức Trừu tượng phải được thực hiện bởi lớp con. Một lớp Trừu tượng có thể có các phương thức bình thường với việc triển khai. Lớp trừu tượng cũng có thể có các biến lớp bên cạnh Sự kiện, Đại biểu, Thuộc tính và Phương thức. Một lớp chỉ có thể thực hiện một lớp trừu tượng chỉ do không tồn tại Đa kế thừa trong C #.

  1. Sau tất cả những điều đó, người phỏng vấn đã đưa ra câu hỏi "Điều gì sẽ xảy ra nếu bạn có một lớp Trừu tượng chỉ với các phương thức trừu tượng? Làm thế nào nó khác với một giao diện?" Tôi không biết câu trả lời nhưng tôi nghĩ đó là sự kế thừa như đã nói ở trên phải không?

  2. Một người phỏng vấn khác hỏi tôi rằng nếu bạn có một biến Công khai trong giao diện thì nó sẽ khác với Lớp Trừu tượng như thế nào? Tôi khẳng định bạn không thể có một biến công khai trong một giao diện. Tôi không biết anh muốn nghe gì nhưng anh cũng không hài lòng.

Xem thêm :


412
Trong khi tôi nghĩ điều quan trọng là phải biết sự khác biệt giữa hai người, đây không phải là một câu hỏi phỏng vấn hay, imo. Trừ khi công việc đang viết một cuốn sách về các chủ đề OO. Bạn tốt hơn không làm việc cho những con dơi ding.
Alan

107
@Alan: Tôi thực sự thích câu hỏi này như một câu hỏi phỏng vấn, nhưng tôi sẽ không nói với ai đó theo cách này - tôi có thể đăng nó giống như "Bạn sẽ chọn giao diện nào trên một lớp cơ sở trừu tượng, khi xác định thứ bậc? ", Hoặc một cái gì đó tương tự.
Reed Copsey

11
Có lẽ họ sau một câu trả lời tập trung vào thiết kế hơn ... mặc dù giống như bạn, tôi sẽ coi nó như một câu hỏi kỹ thuật.
RèmDog

16
Sự khác biệt bảng đẹp ở đây: mindprod.com/jgloss/interfacevsabab.html
Rajat_R

30
@Kave: I insisted you can't have a public variable inside an interface.Tôi nghĩ giao diện có thể có biến công khai. Trong thực tế các biến trong giao diện được tự động công khai và cuối cùng.
một người học

Câu trả lời:


746

Mặc dù câu hỏi của bạn chỉ ra đó là "OO chung", nhưng nó thực sự tập trung vào việc sử dụng .NET các thuật ngữ này.

Trong .NET (tương tự với Java):

  • giao diện có thể không có trạng thái hoặc thực hiện
  • một lớp thực hiện một giao diện phải cung cấp việc thực hiện tất cả các phương thức của giao diện đó
  • các lớp trừu tượng có thể chứa trạng thái (thành viên dữ liệu) và / hoặc triển khai (phương thức)
  • các lớp trừu tượng có thể được kế thừa mà không cần thực hiện các phương thức trừu tượng (mặc dù một lớp dẫn xuất như vậy là chính nó trừu tượng)
  • các giao diện có thể là đa kế thừa, các lớp trừu tượng có thể không (đây có thể là lý do cụ thể chính để các giao diện tồn tại tách biệt với các lớp rút gọn - chúng cho phép thực hiện nhiều kế thừa loại bỏ nhiều vấn đề của MI chung).

Theo các thuật ngữ OO chung, sự khác biệt không nhất thiết phải được xác định rõ. Ví dụ, có những lập trình viên C ++ có thể giữ các định nghĩa cứng nhắc tương tự (giao diện là một tập hợp con nghiêm ngặt của các lớp trừu tượng không thể chứa triển khai), trong khi một số người có thể nói rằng một lớp trừu tượng với một số triển khai mặc định vẫn là giao diện hoặc không trừu tượng lớp vẫn có thể định nghĩa một giao diện.

Thật vậy, có một thành ngữ C ++ được gọi là Giao diện không ảo (NVI) trong đó các phương thức công khai là các phương thức không ảo 'thunk' thành các phương thức ảo riêng tư:


7
Cảm ơn bạn. Tôi nghĩ vì câu trả lời của bạn đề cập đến trạng thái + một tổng quan tốt về tất cả phần còn lại, tôi đánh dấu câu trả lời của bạn là câu trả lời cuối cùng. Bạn nói đúng, tôi đã hỏi về OO chung, vì người phỏng vấn đầu tiên của tôi đã hỏi về OO chung, nhưng vì tôi là một người C #, tôi có xu hướng quên điều đó. ;-) Cũng cảm ơn lời giải thích của C ++, như mọi khi c ++ luôn thổi hồn.
Houman

6
Tôi nghĩ một điểm mấu chốt trong lời giải thích mà Michael cung cấp là khi thực hiện giao diện, bạn PHẢI thực hiện tất cả các thành viên trong giao diện, nhưng khi kế thừa từ một lớp trừu tượng, nó không BẮT BUỘC bởi một lớp con để thực hiện các thành viên của cha mẹ
Guillermo Gomez

82
+1: Tôi sẵn sàng đặt cược rằng những con khỉ đó tổ chức cuộc phỏng vấn thậm chí không nhận ra rằng các ngôn ngữ khác thực hiện OO khác nhau.
Các cuộc đua nhẹ nhàng trong quỹ đạo

2
@JL Tôi không thấy vấn đề nằm ở đâu. Bạn dường như đã nhầm lẫn phương thức trừu tượng với lớp trừu tượng. Phương pháp trừu tượng không có thực hiện. Tuy nhiên, bên trong một lớp trừu tượng , một số phương thức có thể là trừu tượng (nghĩa là không thực hiện) trong khi một số phương thức khác thực sự có thể có triển khai.
xji

19
Lưu ý rằng trong Java 8, bây giờ bạn có thể có các phương thức mặc định và phương thức tĩnh trong các giao diện, điều đó có nghĩa là các giao diện Java có thể có triển khai. Tham khảo tại đây . Rõ ràng bạn đã đề cập chủ yếu đến .NET, vì vậy đây chỉ là một quan sát đề cập đến Java.
davtom

867

Làm thế nào về một sự tương tự: khi tôi còn ở Không quân, tôi đã đi đào tạo phi công và trở thành một phi công của USAF (Không quân Hoa Kỳ). Vào thời điểm đó, tôi không đủ điều kiện để bay bất cứ thứ gì, và phải tham gia khóa huấn luyện loại máy bay. Khi tôi đủ điều kiện, tôi là phi công (lớp Trừu tượng) và phi công C-141 (lớp bê tông). Tại một trong những nhiệm vụ của tôi, tôi được giao một nhiệm vụ bổ sung: Nhân viên an toàn. Bây giờ tôi vẫn là một phi công và một phi công C-141, nhưng tôi cũng đã thực hiện các nhiệm vụ của Nhân viên an toàn (tôi đã thực hiện ISafeOfficer, có thể nói như vậy). Một phi công không bắt buộc phải là nhân viên an toàn, những người khác cũng có thể làm điều đó.

Tất cả các phi công của USAF phải tuân theo một số quy định nhất định của Không quân, và tất cả các phi công C-141 (hoặc F-16 hoặc T-38) 'đều là phi công của USAF. Bất cứ ai cũng có thể là một nhân viên an toàn. Vì vậy, để tóm tắt:

  • Thí điểm: lớp trừu tượng
  • Phi công C-141: lớp bê tông
  • Cán bộ an toàn: giao diện

thêm lưu ý: điều này có nghĩa là một sự tương tự để giúp giải thích khái niệm này, không phải là một khuyến nghị mã hóa. Xem các ý kiến ​​khác nhau dưới đây, các cuộc thảo luận là thú vị.


87
Tôi thực sự thích sự tương tự này, nó sử dụng một ví dụ đơn giản để giải thích một chủ đề hơi phức tạp
Kevin Bowersox

13
Đây là cách tốt nhất để hiểu thuật ngữ OO phức tạp. Nói tóm lại, tất cả lý thuyết chỉ có giá trị khi bạn có thể sử dụng nó một cách thực tế. @Jay bạn rexample thực sự rất dễ nắm bắt sau đó một vài gạch đầu dòng (chủ yếu là thâm nhập tâm trí thay vì bị hấp thụ!)
so với

54
Tôi vẫn còn một chút bối rối. Giả sử, bây giờ bạn đã có bằng cấp F-16 và T-38, vì vậy bây giờ lớp Jaykhông thể kế thừa từ nhiều lớp (phi công C-141, phi công F-16 và phi công T-38), điều đó có nghĩa là các lớp của ai sẽ trở thành giao diện? Cảm ơn
Alex Okrushko

37
Rất nhiều người đã đưa ra +1 cho nhận xét của Alex, vì nó cho thấy một số điểm yếu trong ví dụ này. Đầu tiên, tôi sẽ nói rằng Jay sẽ là một ví dụ của C-141Pilot chứ không phải là lớp học riêng của nó. Ngoài ra, vì ở USAF, 99% tất cả các phi công chỉ đủ điều kiện trong một máy bay tại một thời điểm (FCF và các phi công thử nghiệm là trường hợp ngoại lệ đáng chú ý) Tôi đã không xem xét nhiều bằng cấp và cách thực hiện. Như tôi biết về một phi công, 50 năm trước, đã đủ điều kiện trong 25 máy bay khác nhau, tôi nghĩ rằng điều đó minh họa cách chúng ta KHÔNG muốn sử dụng nhiều kế thừa.
Jay

20
Vì không thể một phi công bay nhiều máy bay cùng một lúc, nên đây sẽ là cơ hội tốt để thực hiện mô hình chiến lược. Một phi công sẽ có một bộ chứng chỉ và chọn đúng chứng chỉ khi chạy. Các chứng chỉ sẽ được mã hóa thành các hành vi sẽ thực hiện giao diện IFlyPlane, với các phương thức Take Offer, Land, Eject.
Michael Blackburn

221

Tôi nghĩ rằng câu trả lời họ đang tìm kiếm là sự khác biệt cơ bản hoặc triết lý của OPPS.

Kế thừa lớp trừu tượng được sử dụng khi lớp dẫn xuất chia sẻ các thuộc tính và hành vi cốt lõi của lớp trừu tượng. Các loại hành vi thực sự xác định lớp.

Mặt khác, kế thừa giao diện được sử dụng khi các lớp chia sẻ hành vi ngoại vi, các lớp không nhất thiết phải định nghĩa lớp dẫn xuất.

Ví dụ. Xe hơi và Xe tải chia sẻ nhiều đặc tính và hành vi cốt lõi của lớp trừu tượng Ô tô, nhưng chúng cũng chia sẻ một số hành vi ngoại vi như Tạo khí thải mà ngay cả các lớp không ô tô như Máy khoan hoặc PowerGenerators chia sẻ và không nhất thiết phải định nghĩa Xe hoặc Xe tải , vì vậy Car, Truck, Driller và PowerGenerator đều có thể chia sẻ cùng một giao diện IExTHER.


32
Tôi nghĩ rằng một sự tương tự thậm chí tốt hơn sẽ là "usedFuel" sẽ thể hiện bản chất hợp đồng của giao diện.
Pureferret

@Pureferret nếu acceleratelà một phần trong hành vi cốt lõi của lớp trừu tượng Ô tô, thì tôi không thể nói acceleratethể hiện bản chất hợp đồng . bản chất hợp đồng là gì? Tại sao từ này được contractgiới thiệu bất cứ khi nào chúng ta nói về interface?
trao đổi quá mức

@overexchange vì thông thường giao diện chỉ là nơi hai 'bề mặt' gặp nhau, nhưng hợp đồng từ ngụ ý có một thỏa thuận về cách hai 'bề mặt' gặp nhau. Điều đó không có nghĩa (ít nhất là với tôi) rằng việc tạo ra khí thải là thứ bạn 'đồng ý'. Nhưng nó có ý nghĩa (một lần nữa với tôi) rằng bạn có thể đồng ý về việc cần sử dụng nhiên liệu.
Pureferret

1
@Pureferret tôi đã đưa ra một truy vấn tại liên kết tương tự
trao đổi quá mức vào

1
@Pureferret nếu interfacecần phải có hành vi ngoại vi, thì tại sao lại public interface List<E> extends Collection<E> {}được thiết kế để mô tả hành vi cốt lõi của list? điều này thực sự mâu thuẫn với câu trả lời của prasun. Cả hai Collection<E>List<E>là giao diện ở đây.
trao đổi quá mức

198

Ngắn gọn: Các lớp trừu tượng được sử dụng để Mô hình hóa một hệ thống phân cấp lớp của các lớp trông tương tự (Ví dụ: Animal có thể là lớp trừu tượng và Human, Lion, Tiger có thể là các lớp dẫn xuất cụ thể)

Giao diện được sử dụng để liên lạc giữa 2 lớp tương tự / không giống nhau, không quan tâm đến loại của lớp triển khai Giao diện (ví dụ: Chiều cao có thể là thuộc tính giao diện và nó có thể được thực hiện bởi Con người, Tòa nhà, Cây. , bạn có thể bơi bạn có thể chết hoặc bất cứ điều gì .. nó chỉ quan trọng một điều mà bạn cần phải có Chiều cao (thực hiện trong lớp học của bạn)).


7
Tôi thực sự thích câu trả lời này bởi vì đôi khi rất khó để trả lời "cái gì" khác nhau giữa các thứ bằng cách nhìn vào một cái gì đó trừu tượng hơn như ý định , thay vì chỉ cấu trúc (như về mặt cấu trúc, một giao diện và một lớp trừu tượng thuần túy khá giống nhau Điều).
LostSalad

Thật dễ dàng để liệt kê những gì một lớp trừu tượng so với một giao diện có thể làm trong một ngôn ngữ cụ thể nhưng khó khăn hơn để tạo ra một sự trừu tượng để đưa ra ý nghĩa và trách nhiệm đối với và những gì bạn nói hoàn toàn tiếp tục sử dụng khái niệm 2 trong OO. Cảm ơn!
Samuel

2
@dhananjay: tôi thấy làm thế nào Chiều cao có thể tách rời khỏi khái niệm của lớp Thú và có thể từ một lớp khác, nhưng chính xác thì bạn có ý gì khi "giao tiếp" giữa các lớp? Nó chỉ đơn giản là chỉ định nghĩa Chiều cao cho lớp của chính nó, đúng không?
TTT

77

Có một vài sự khác biệt khác -

Các giao diện không thể có bất kỳ triển khai cụ thể. Các lớp cơ sở trừu tượng có thể. Điều này cho phép bạn cung cấp thực hiện cụ thể ở đó. Điều này có thể cho phép một lớp cơ sở trừu tượng thực sự cung cấp một hợp đồng chặt chẽ hơn, giao diện thực sự chỉ mô tả cách sử dụng một lớp. (Lớp cơ sở trừu tượng có thể có các thành viên không ảo xác định hành vi, điều này mang lại nhiều quyền kiểm soát hơn cho tác giả của lớp cơ sở.)

Nhiều giao diện có thể được thực hiện trên một lớp. Một lớp chỉ có thể xuất phát từ một lớp cơ sở trừu tượng duy nhất. Điều này cho phép phân cấp đa hình bằng các giao diện, nhưng không phải là các lớp cơ sở trừu tượng. Điều này cũng cho phép giả thừa kế đa giao diện bằng cách sử dụng các giao diện.

Các lớp cơ sở trừu tượng có thể được sửa đổi trong v2 + mà không phá vỡ API. Thay đổi giao diện đang phá vỡ những thay đổi.

[C # /. NET Cụ thể] Các giao diện, không giống như các lớp cơ sở trừu tượng, có thể được áp dụng cho các loại giá trị (cấu trúc). Cấu trúc không thể kế thừa từ các lớp cơ sở trừu tượng. Điều này cho phép các hợp đồng hành vi / hướng dẫn sử dụng được áp dụng trên các loại giá trị.


5
+1 cho điểm chính mà nhiều giao diện có thể được thực hiện trên một lớp.
cgp

Đó là một lợi thế thực sự cho các giao diện trên các lớp cơ sở trừu tượng, IMO. Mặt khác, tôi đồng ý với các nguyên tắc thiết kế .NET, giờ đây nói rằng "thích các lớp cơ sở trừu tượng hơn các giao diện"
Reed Copsey

Mặc dù, sẽ rất quan trọng nếu bạn có thể thêm điểm rằng giao diện cũng có thể được áp dụng cho bất kỳ lớp nào.
cgp

1
@altCognito: Hình là loại được xử lý với đoạn thứ hai. Tuy nhiên, điều này đã nhắc nhở tôi rằng các giao diện hoạt động trên các loại giá trị, vì vậy tôi đã thêm nó.
Sậy Copsey

Cảm ơn bạn rất nhiều cho mô tả chính xác này. Nó thực sự rất hữu ích. Tôi là người mới ở đây. Thật đáng tiếc khi bạn không thể chọn hai câu trả lời là "câu trả lời". Một điều làm tôi bối rối là việc bạn sử dụng lớp Tóm tắt 'cơ sở'. Tất cả các lớp trừu tượng có nghĩa là một lớp cơ sở của một lớp con. Tại sao đặt tên thêm 'cơ sở'?
Houman

68

Kế thừa
Xem xét một chiếc xe hơi và một chiếc xe buýt. Chúng là hai phương tiện khác nhau. Tuy nhiên, họ vẫn chia sẻ một số thuộc tính phổ biến như chúng có tay lái, phanh, bánh răng, động cơ, v.v.
Vì vậy, với khái niệm thừa kế, điều này có thể được biểu diễn như sau ...

public class Vehicle {
    private Driver driver;
    private Seat[] seatArray; //In java and most of the Object Oriented Programming(OOP) languages, square brackets are used to denote arrays(Collections).
    //You can define as many properties as you want here ...
}

Bây giờ là một chiếc xe đạp ...

public class Bicycle extends Vehicle {
    //You define properties which are unique to bicycles here ...
    private Pedal pedal;
}

Và một chiếc xe hơi ...

public class Car extends Vehicle {
    private Engine engine;
    private Door[] doors;
}

Đó là tất cả về Kế thừa . Chúng tôi sử dụng chúng để phân loại các đối tượng thành các hình thức cơ bản đơn giản hơn và con cái của chúng như chúng ta đã thấy ở trên.

Lớp học trừu tượng

Các lớp trừu tượng là các đối tượng không đầy đủ . Để hiểu rõ hơn, chúng ta hãy xem xét sự tương tự xe một lần nữa.
Một chiếc xe có thể được lái. Đúng? Nhưng các phương tiện khác nhau được điều khiển theo những cách khác nhau ... Ví dụ: Bạn không thể lái xe giống như bạn lái Xe đạp.
Vậy làm thế nào để thể hiện chức năng lái xe của một chiếc xe? Khó kiểm tra loại xe nào hơn và lái nó với chức năng riêng của nó; bạn sẽ phải thay đổi lớp Driver nhiều lần khi thêm một loại phương tiện mới.
Ở đây có vai trò của các lớp và phương thức trừu tượng. Bạn có thể định nghĩa phương thức ổ đĩa là trừu tượng để nói rằng mọi trẻ em thừa kế phải thực hiện chức năng này.
Vì vậy, nếu bạn sửa đổi lớp xe ...

//......Code of Vehicle Class
abstract public void drive();
//.....Code continues

Xe đạp và xe hơi cũng phải chỉ định cách lái nó. Nếu không, mã sẽ không được biên dịch và một lỗi được đưa ra.
Nói tóm lại .. một lớp trừu tượng là một lớp không hoàn chỉnh một phần với một số hàm không hoàn chỉnh, mà các con kế thừa phải chỉ định riêng của chúng.

Giao diện Giao diện hoàn toàn không đầy đủ. Họ không có bất kỳ tài sản. Họ chỉ cho thấy rằng những đứa trẻ được thừa kế có khả năng làm điều gì đó ...
Giả sử bạn có các loại điện thoại di động khác nhau với bạn. Mỗi người trong số họ có những cách khác nhau để làm các chức năng khác nhau; Vd: gọi một người. Nhà sản xuất điện thoại chỉ định cách thực hiện. Ở đây, điện thoại di động có thể quay số - nghĩa là có thể quay số. Hãy thể hiện điều này như một giao diện.

public interface Dialable {
    public void dial(Number n);
}

Ở đây, người tạo ra Dialable định nghĩa cách quay số. Bạn chỉ cần cho nó một số để quay số.

// Makers define how exactly dialable work inside.

Dialable PHONE1 = new Dialable() {
    public void dial(Number n) {
        //Do the phone1's own way to dial a number
    }
}

Dialable PHONE2 = new Dialable() {
    public void dial(Number n) {
        //Do the phone2's own way to dial a number
    }
}


//Suppose there is a function written by someone else, which expects a Dialable
......
public static void main(String[] args) {
    Dialable myDialable = SomeLibrary.PHONE1;
    SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....

Bằng cách sử dụng các giao diện thay vì các lớp trừu tượng, người viết hàm sử dụng Dialable không cần phải lo lắng về các thuộc tính của nó. Ví dụ: Nó có màn hình cảm ứng hoặc bàn phím quay số, Đây có phải là điện thoại cố định hoặc điện thoại di động. Bạn chỉ cần biết nếu nó có thể quay số được; nó có kế thừa (hoặc thực hiện) giao diện Dialable.

Và quan trọng hơn , nếu một ngày nào đó, bạn chuyển đổi Dialable bằng một cái khác

......
public static void main(String[] args) {
    Dialable myDialable = SomeLibrary.PHONE2; // <-- changed from PHONE1 to PHONE2
    SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....

Bạn có thể chắc chắn rằng mã vẫn hoạt động hoàn hảo vì chức năng sử dụng tính năng quay số không (và không thể) phụ thuộc vào các chi tiết khác với các chi tiết được chỉ định trong giao diện Quay số. Cả hai đều thực hiện giao diện Có thể quay được và đó là điều duy nhất mà chức năng quan tâm.

Các giao diện thường được các nhà phát triển sử dụng để đảm bảo khả năng tương tác (sử dụng thay thế cho nhau) giữa các đối tượng, miễn là chúng có chung chức năng (giống như bạn có thể đổi sang điện thoại cố định hoặc điện thoại di động, chỉ cần bạn quay số). Nói tóm lại, giao diện là một phiên bản đơn giản hơn của các lớp trừu tượng, không có thuộc tính nào.
Ngoài ra, lưu ý rằng bạn có thể triển khai (kế thừa) nhiều giao diện như bạn muốn nhưng bạn chỉ có thể mở rộng (kế thừa) một lớp cha duy nhất.

Thông tin thêm Các lớp trừu tượng vs Giao diện


Không phải là "Giao diện không có bất kỳ thuộc tính nào".
Bigeyes

@Bigeyes, java không cho phép các thuộc tính trong giao diện. Tôi nghĩ rằng nó cũng giống nhau trong các ngôn ngữ khác. Bạn có thể vui lòng giải thích thêm?
fz_salam

Tôi đang đề cập đến C # /. Net. Vui lòng xem ví dụ
Bigeyes

@Bigeyes cho C # nơi giao diện có thể có các thuộc tính, không phải điều đó giới thiệu lại vấn đề thừa kế? Điều gì xảy ra khi một lớp sử dụng nhiều giao diện đã xác định cùng một thuộc tính? Chỉ tò mò cảm ơn
stackPizer

@happycoder: re: "Ở đây bằng cách sử dụng giao diện thay vì các lớp trừu tượng, bạn không cần phải lo lắng về các thuộc tính của nó. Ví dụ: Nó có màn hình cảm ứng hoặc bàn phím quay số, Đây có phải là điện thoại cố định hoặc điện thoại di động. Bạn chỉ cần biết nếu nó có thể quay được, nó có kế thừa (hoặc thực hiện) giao diện Có thể quay được không. " - bạn có thể hiển thị điều này trong một ví dụ mã không, cũng không thấy nó sẽ được kế thừa như thế nào ...
TTT

45

Nếu bạn coi javalà ngôn ngữ OOP để trả lời câu hỏi này, bản phát hành Java 8 khiến một số nội dung trong các câu trả lời ở trên bị lỗi thời. Bây giờ giao diện java có thể có các phương thức mặc định với việc thực hiện cụ thể.

Trang web của Oracle cung cấp sự khác biệt chính giữa interfaceabstractlớp.

Cân nhắc sử dụng các lớp trừu tượng nếu:

  1. Bạn muốn chia sẻ mã giữa một số lớp liên quan chặt chẽ.
  2. Bạn mong đợi rằng các lớp mở rộng lớp trừu tượng của bạn có nhiều phương thức hoặc trường phổ biến hoặc yêu cầu các công cụ sửa đổi truy cập khác ngoài công khai (như được bảo vệ và riêng tư).
  3. Bạn muốn khai báo các trường không tĩnh hoặc không cuối cùng.

Cân nhắc sử dụng các giao diện nếu:

  1. Bạn mong đợi rằng các lớp không liên quan sẽ thực hiện giao diện của bạn. Ví dụ, nhiều đối tượng không liên quan có thể thực hiện Serializablegiao diện.
  2. Bạn muốn chỉ định hành vi của một loại dữ liệu cụ thể, nhưng không quan tâm đến việc ai thực hiện hành vi của nó.
  3. Bạn muốn tận dụng lợi thế của nhiều kiểu thừa kế.

Nói một cách đơn giản, tôi muốn sử dụng

giao diện: Để thực hiện hợp đồng bởi nhiều đối tượng không liên quan

lớp trừu tượng: Để thực hiện cùng một hành vi hoặc khác nhau giữa nhiều đối tượng liên quan

Hãy xem ví dụ về mã để hiểu mọi thứ theo cách rõ ràng: Tôi nên giải thích sự khác biệt giữa Giao diện và lớp Trừu tượng như thế nào?


33

Những người phỏng vấn đang sủa lên một cây kỳ lạ. Đối với các ngôn ngữ như C # và Java, có một sự khác biệt, nhưng trong các ngôn ngữ khác như C ++ thì không có. Lý thuyết OO không phân biệt hai loại, chỉ đơn thuần là cú pháp của ngôn ngữ.

Một lớp trừu tượng là một lớp có cả triển khai và giao diện (các phương thức ảo thuần túy) sẽ được kế thừa. Các giao diện nói chung không có bất kỳ triển khai nào mà chỉ có các hàm ảo thuần túy.

Trong C # hoặc Java, một lớp trừu tượng không có bất kỳ triển khai nào khác với một giao diện chỉ theo cú pháp được sử dụng để kế thừa từ nó và thực tế bạn chỉ có thể kế thừa từ một giao diện.


Tôi đã được hỏi cùng một câu hỏi một tuần trước, tôi không có kinh nghiệm với Java nhưng tôi đã làm việc với C ++ được một thời gian rồi. Người phỏng vấn không chỉ định ngôn ngữ trước khi đặt câu hỏi, vì vậy tôi chỉ giải thích rằng các giao diện trong trường hợp này là các lớp trừu tượng không có trạng thái hoặc triển khai dưới bất kỳ hình thức nào. Tôi đồng ý rằng đó là một câu hỏi kỳ lạ quá.
dacabdi

31

Bằng cách triển khai các giao diện, bạn sẽ đạt được thành phần (các mối quan hệ "có-a") thay vì kế thừa (các mối quan hệ "is-a"). Đó là một nguyên tắc quan trọng cần nhớ khi nói đến những thứ như các mẫu thiết kế nơi bạn cần sử dụng các giao diện để đạt được một thành phần của các hành vi thay vì thừa kế.


17
Các giao diện đạt được, IMO, nhiều hơn về mối quan hệ "Hành vi như một". Đóng gói đạt được thành phần tốt hơn so với một giao diện.
Reed Copsey

12
Tôi không nghĩ việc thực hiện giao diện sẽ đến theo thành phần.
Pavan Dittakavi

Thêm vào đó, giao diện nhiều khả năng sử dụng để mô tả "khả năng", như IDis Dùng. Nó được sử dụng để chia sẻ chức năng giữa các lớp mà các lớp này "có thể làm" một cái gì đó. Ví dụ khác IFlyable có thể được thực hiện bằng chim và máy bay. Nhưng Bird có thể xuất phát từ Class Creature nơi airecraft xuất phát từ AirCraft.
Peter.Wang

26

tôi sẽ giải thích chi tiết sâu về giao diện và lớp trừu tượng. Nếu bạn biết tổng quan về giao diện và lớp trừu tượng, thì câu hỏi đầu tiên xuất hiện trong đầu bạn khi chúng ta nên sử dụng Giao diện và khi nào chúng ta nên sử dụng lớp Trừu tượng. Vì vậy, vui lòng kiểm tra giải thích bên dưới về lớp Giao diện và Tóm tắt.

  1. Khi nào chúng ta nên sử dụng Giao diện?

    Nếu bạn không biết về triển khai, chúng tôi có yêu cầu kỹ thuật thì chúng tôi sẽ sử dụng Giao diện

  2. Khi nào chúng ta nên sử dụng Lớp trừu tượng?

    nếu bạn biết thực hiện nhưng không hoàn toàn (thực hiện một phần) thì chúng ta sẽ đi với lớp Trừu tượng.

    Giao diện

    mọi phương thức theo mặc định công khai trừu tượng có nghĩa là giao diện hoàn toàn trừu tượng 100%.

    trừu tượng

    có thể có phương thức Concrete và phương thức Trừu tượng, phương thức Concrete là gì, có triển khai trong lớp Trừu tượng, Một lớp trừu tượng là một lớp được khai báo trừu tượng, nó có thể hoặc không bao gồm các phương thức trừu tượng.

    Giao diện

    Chúng tôi không thể khai báo giao diện là riêng tư, được bảo vệ

    Q. Tại sao chúng tôi không tuyên bố Giao diện là riêng tư và được bảo vệ?

    Bởi vì theo phương thức giao diện mặc định là trừu tượng công khai và vì vậy đó là lý do mà chúng tôi không khai báo giao diện là riêng tư và được bảo vệ.

    Phương thức giao diện
    chúng ta cũng không thể khai báo giao diện là riêng tư, được bảo vệ, cuối cùng, tĩnh, đồng bộ hóa, gốc .....

    Tôi sẽ đưa ra lý do: tại sao chúng tôi không khai báo phương thức đồng bộ hóa vì chúng tôi không thể tạo đối tượng của giao diện và đồng bộ hóa đang hoạt động trên đối tượng và vì vậy lý do chúng tôi không khai báo phương thức đồng bộ Khái niệm thoáng qua cũng không thể áp dụng được vì công việc tạm thời được đồng bộ hóa.

    trừu tượng

    chúng tôi đang vui vẻ sử dụng với công khai, tĩnh cuối cùng .... có nghĩa là không có giới hạn nào được áp dụng một cách trừu tượng.

    Giao diện

    Các biến được khai báo trong Giao diện dưới dạng cuối cùng tĩnh công khai mặc định, vì vậy chúng tôi cũng không được khai báo biến là riêng tư, được bảo vệ.

    Công cụ sửa đổi dễ bay hơi cũng không thể áp dụng trong giao diện vì biến giao diện theo mặc định là biến cuối cùng và biến cuối cùng tĩnh, bạn không thể thay đổi giá trị một khi nó gán giá trị thành biến và một khi bạn đã khai báo biến vào giao diện, bạn phải gán biến.

    Và biến động là tiếp tục thay đổi vì vậy nó là opp. để cuối cùng đó là lý do chúng tôi không sử dụng biến dễ bay hơi trong giao diện.

    trừu tượng

    Tóm tắt biến không cần khai báo tĩnh cuối cùng.

tôi hy vọng bài viết này hữu ích


4
Tôi không đồng ý với điểm này: Abstract class must have at lease one abstract method.Có thể có một lớp Trừu tượng mà không có phương thức Trừu tượng, miễn là bạn triển khai nó. TÀI LIỆU THAM KHẢO: An abstract class is a class that is declared abstract—it may or may not include abstract methods.NGUỒN TÀI LIỆU THAM KHẢO: docs.oracle.com/javase/tutorial/java/IandI/abauge.html
Devner

Bạn đang nói về chi tiết kỹ thuật và triển khai, bạn không trả lời câu hỏi về mặt chung của OOP
Billal Begueradj

26

Nói một cách khái niệm, giữ cho việc thực hiện cụ thể ngôn ngữ, quy tắc, lợi ích và đạt được bất kỳ mục tiêu lập trình nào bằng cách sử dụng bất kỳ ai hoặc cả hai, có thể hoặc không thể có mã / dữ liệu / tài sản, blah blah, một hoặc nhiều kế thừa, tất cả sang một bên

1- Lớp trừu tượng (hoặc trừu tượng thuần túy) có nghĩa là để thực hiện phân cấp. Nếu các đối tượng kinh doanh của bạn trông hơi giống cấu trúc, chỉ đại diện cho một loại mối quan hệ cha-con (phân cấp) thì lớp kế thừa / lớp trừu tượng sẽ được sử dụng. Nếu mô hình kinh doanh của bạn không có hệ thống phân cấp thì không nên sử dụng kế thừa (ở đây tôi không nói về logic lập trình, ví dụ như một số mẫu thiết kế yêu cầu kế thừa). Về mặt khái niệm, lớp trừu tượng là một phương thức để thực hiện phân cấp mô hình kinh doanh trong OOP, nó không liên quan gì đến Giao diện, thực sự so sánh lớp Trừu tượng với Giao diện là vô nghĩa vì cả hai đều là những thứ hoàn toàn khác nhau về mặt khái niệm, nó được yêu cầu trong các cuộc phỏng vấn chỉ để kiểm tra các khái niệm vì có vẻ cả hai đều cung cấp một số chức năng giống nhau khi thực hiện và chúng tôi lập trình viên thường nhấn mạnh nhiều hơn vào mã hóa. [Hãy ghi nhớ điều này cũng như Trừu tượng khác với Lớp trừu tượng].

2- Giao diện là một hợp đồng, một chức năng kinh doanh hoàn chỉnh được đại diện bởi một hoặc nhiều bộ chức năng. Đó là lý do tại sao nó được thực hiện và không được kế thừa. Một đối tượng kinh doanh (một phần của hệ thống phân cấp hoặc không) có thể có bất kỳ số lượng chức năng kinh doanh hoàn chỉnh. Nó không có gì để làm với các lớp trừu tượng có nghĩa là thừa kế nói chung. Ví dụ, một con người có thể CHẠY, một con voi có thể CHẠY, một con chim có thể CHẠY, v.v., tất cả các đối tượng có thứ bậc khác nhau này sẽ thực hiện giao diện RUN hoặc giao diện EAT hoặc SPEAK. Đừng đi vào triển khai vì bạn có thể triển khai nó như có các lớp trừu tượng cho từng loại thực hiện các giao diện này. Một đối tượng của bất kỳ hệ thống phân cấp nào cũng có thể có chức năng (giao diện) không liên quan gì đến hệ thống phân cấp của nó.

Tôi tin rằng, Giao diện không được phát minh để đạt được nhiều kế thừa hoặc để lộ hành vi công khai, và tương tự, các lớp trừu tượng thuần túy không được ghi đè lên giao diện nhưng Giao diện là chức năng mà một đối tượng có thể thực hiện (thông qua các chức năng của giao diện đó) và Lớp trừu tượng đại diện cho cha mẹ của một hệ thống phân cấp để sinh ra những đứa trẻ có cấu trúc cốt lõi (thuộc tính + chức năng) của cha mẹ

Khi bạn được hỏi về sự khác biệt, đó thực sự là sự khác biệt về khái niệm không phải là sự khác biệt trong việc thực hiện cụ thể theo ngôn ngữ trừ khi được hỏi rõ ràng.

Tôi tin rằng, cả hai người phỏng vấn đều mong đợi một sự khác biệt rõ ràng giữa hai điều này và khi bạn thất bại, họ đã cố gắng đưa bạn đến sự khác biệt này bằng cách thực hiện MỘT là KHÁC

Điều gì nếu bạn có một lớp Trừu tượng chỉ với các phương thức trừu tượng?


Điều đó khá nhiều tổng hợp câu trả lời cho câu hỏi này khá tốt.
pranavn

Chức năng thực hiện so với cấu trúc mở rộng, tốt đẹp!
khắc nghiệt

21

Đối với .Net,

Câu trả lời của bạn cho Người phỏng vấn thứ hai cũng là câu trả lời cho câu hỏi thứ nhất ... Các lớp trừu tượng có thể có triển khai, và trạng thái, giao diện không thể ...

EDIT: Trên một lưu ý khác, tôi thậm chí sẽ không sử dụng cụm từ 'lớp con' (hoặc cụm từ 'thừa kế') để mô tả các lớp được 'xác định để thực hiện' một giao diện. Đối với tôi, một giao diện là một định nghĩa về hợp đồng mà một lớp phải tuân theo nếu nó đã được định nghĩa để 'thực hiện' giao diện đó. Nó không kế thừa bất cứ điều gì ... Bạn phải tự mình thêm mọi thứ.


2
Đúng! Tiểu bang! Đó là ý nghĩa của người phỏng vấn thứ hai với cách nói "biến công khai" trong giao diện. trời ạ Các lớp trừu tượng có thể có trạng thái, giao diện không thể! Và vâng, tất cả những người khác cũng đồng ý về sự khác biệt giữa cách thừa kế của họ, điều mà tôi đã quên đề cập đến nhưng đã tìm ra sau đó. :) Cảm ơn mọi người!
Houman

4
Không chỉ là trạng thái .... Các lớp trừu tượng có thể có THỰC HIỆN. tức là, họ có thể có các phương thức với mã trong đó thực sự chạy và làm một cái gì đó, được nhập vào và được thực thi bởi các thể hiện của các lớp cơ sở ... Không như vậy với các giao diện
Charles Bretana

Thậm chí hơn thế, theo một nghĩa nào đó, các lớp Trừu tượng có thể được khởi tạo, chúng chỉ cần được khởi tạo bằng cách sử dụng một định nghĩa lớp dẫn xuất, không trực tiếp. Nhưng các biến trạng thái được định nghĩa trong lớp trừu tượng được khởi tạo trong đối tượng được tạo bằng cách tạo mới một thể hiện của lớp dẫn xuất. Ví dụ này là một thể hiện của lớp trừu tượng cũng như là một thể hiện của lớp dẫn xuất - sau tất cả là xuất phát từ nó. Không có điều này là đúng cho một giao diện.
Charles Bretana

Khi bạn tạo một thể hiện của một lớp được xác định để thực hiện một giao diện, nó không phải là một "thể hiện" của giao diện đó, tất cả các cú pháp làm cho trình biên dịch kiểm tra mã cho lớp và đảm bảo rằng mọi hành vi (phương thức, thuộc tính , event, eventHandler, v.v.) được định nghĩa bởi giao diện đã được triển khai trong mã cho lớp.
Charles Bretana

20

Giao diện : nên được sử dụng nếu bạn muốn ngụ ý một quy tắc về các thành phần có thể có hoặc không liên quan đến nhau

Ưu điểm:

  1. Cho phép nhiều kế thừa
  2. Cung cấp sự trừu tượng bằng cách không tiết lộ loại đối tượng chính xác nào đang được sử dụng trong ngữ cảnh
  3. cung cấp sự thống nhất bởi một chữ ký cụ thể của hợp đồng

Nhược điểm:

  1. Phải thực hiện tất cả các hợp đồng được xác định
  2. Không thể có biến hoặc đại biểu
  3. Sau khi xác định không thể thay đổi mà không phá vỡ tất cả các lớp

Lớp trừu tượng : nên được sử dụng khi bạn muốn có một số hành vi hoặc triển khai cơ bản hoặc mặc định cho các thành phần liên quan đến nhau

Ưu điểm:

  1. Nhanh hơn giao diện
  2. Có tính linh hoạt trong việc thực hiện (bạn có thể thực hiện nó đầy đủ hoặc một phần)
  3. Có thể dễ dàng thay đổi mà không phá vỡ các lớp dẫn xuất

Nhược điểm:

  1. Không thể được khởi tạo
  2. Không hỗ trợ nhiều kế thừa

Xác định nhanh hơn. Nó có ý nghĩa không? nó thậm chí còn có ý nghĩa gì? opcode cho chức năng gọi trên một lớp trừu tượng nhanh hơn opcode cho việc gọi chức năng trên một giao diện?
denis631

Lớp trừu tượng @ denis631 nhanh hơn một chút so với giao diện vì tìm kiếm và cuộc gọi có liên quan đến phương thức giao diện. đọc coderanch.com/t/503450/java/abab- class
quản trị trang web bourax

17

Tôi nghĩ rằng họ không thích phản hồi của bạn vì bạn đã đưa ra những khác biệt về kỹ thuật thay vì thiết kế. Câu hỏi giống như một câu hỏi troll đối với tôi. Trong thực tế, các giao diện và các lớp trừu tượng có một bản chất hoàn toàn khác nhau, do đó bạn không thể thực sự so sánh chúng. Tôi sẽ cho bạn tầm nhìn của tôi về vai trò của giao diện và vai trò của lớp trừu tượng là gì.

giao diện: được sử dụng để đảm bảo hợp đồng và thực hiện khớp nối thấp giữa các lớp để có ứng dụng dễ bảo trì hơn, có thể mở rộng và kiểm tra được.

lớp trừu tượng: chỉ được sử dụng để xác định một số mã giữa các lớp có cùng khả năng đáp ứng. Lưu ý rằng đây là lý do chính tại sao đa kế thừa là một điều xấu trong OOP, bởi vì một lớp không nên xử lý nhiều khả năng đáp ứng ( thay vào đó sử dụng thành phần ).

Vì vậy, các giao diện có vai trò kiến ​​trúc thực sự trong khi các lớp trừu tượng hầu như chỉ là một chi tiết triển khai (tất nhiên nếu bạn sử dụng nó một cách chính xác).


13
After all that, the interviewer came up with the question "What if you had an 
Abstract class with only abstract methods? How would that be different
from an interface?" 

Tài liệu nói rõ rằng nếu một lớp trừu tượng chỉ chứa các khai báo phương thức trừu tượng, thì nó nên được khai báo như một giao diện thay thế.

An another interviewer asked me what if you had a Public variable inside
the interface, how would that be different than in Abstract Class?

Các biến trong Giao diện theo mặc định là tĩnh và cuối cùng. Câu hỏi có thể được đóng khung như thế nào nếu tất cả các biến trong lớp trừu tượng là công khai? Vâng, chúng vẫn có thể không tĩnh và không cuối cùng không giống như các biến trong giao diện.

Cuối cùng tôi sẽ thêm một điểm nữa vào những điểm được đề cập ở trên - các lớp trừu tượng vẫn là các lớp và nằm trong một cây thừa kế duy nhất trong khi các giao diện có thể có mặt trong nhiều kế thừa.


13
  1. Giao diện:
    • Chúng tôi không thực hiện (hoặc định nghĩa) các phương thức, chúng tôi làm điều đó trong các lớp dẫn xuất.
    • Chúng tôi không khai báo các biến thành viên trong giao diện.
    • Các giao diện thể hiện mối quan hệ HAS-A. Điều đó có nghĩa là chúng là một mặt nạ của các đối tượng.
  2. Lớp trừu tượng:
    • Chúng ta có thể khai báo và định nghĩa các phương thức trong lớp trừu tượng.
    • Chúng tôi ẩn các nhà xây dựng của nó. Điều đó có nghĩa là không có đối tượng được tạo ra từ nó trực tiếp.
    • Lớp trừu tượng có thể chứa các biến thành viên.
    • Các lớp dẫn xuất kế thừa lớp trừu tượng có nghĩa là các đối tượng từ các lớp dẫn xuất không bị che lấp, nó kế thừa lớp trừu tượng. Mối quan hệ trong trường hợp này là IS-A.

Đây là ý kiến ​​của tôi.


12

Sao chép từ CLR qua C # bởi Jeffrey Richter ...

Tôi thường nghe câu hỏi, tôi nên thiết kế kiểu cơ sở hay giao diện? Câu trả lời không phải lúc nào cũng rõ ràng.

Dưới đây là một số hướng dẫn có thể giúp bạn:

■ - Mối quan hệ IS-A so với CAN-DO Một loại chỉ có thể kế thừa một triển khai. Nếu loại dẫn xuất không thể yêu cầu mối quan hệ IS-A với loại cơ sở, không sử dụng loại cơ sở; sử dụng một giao diện. Giao diện ngụ ý mối quan hệ CAN-DO. Nếu chức năng CAN-DO dường như thuộc về các loại đối tượng khác nhau, hãy sử dụng giao diện. Ví dụ: một loại có thể chuyển đổi các thể hiện của chính nó sang một loại khác (IConvertible), một loại có thể tuần tự hóa một thể hiện của chính nó (ISerializable), v.v ... Lưu ý rằng các loại giá trị phải được lấy từ System.ValueType, và do đó, chúng không thể được dẫn xuất từ một lớp cơ sở tùy ý. Trong trường hợp này, bạn phải sử dụng mối quan hệ CAN-DO và xác định giao diện.

■ - Dễ sử dụng Thông thường, nhà phát triển của bạn dễ dàng xác định loại mới xuất phát từ loại cơ sở hơn là thực hiện tất cả các phương thức của giao diện. Loại cơ sở có thể cung cấp rất nhiều chức năng, vì vậy loại dẫn xuất có lẽ chỉ cần sửa đổi tương đối nhỏ đối với hành vi của nó. Nếu bạn cung cấp một giao diện, loại mới phải thực hiện tất cả các thành viên.

■ - Thực hiện nhất quán Cho dù hợp đồng giao diện được ghi chép tốt đến đâu, rất khó có khả năng mọi người sẽ thực hiện hợp đồng đúng 100%. Trên thực tế, COM gặp phải vấn đề này, đó là lý do tại sao một số đối tượng COM chỉ hoạt động chính xác với Microsoft Word hoặc với Windows Internet Explorer. Bằng cách cung cấp loại cơ sở với triển khai mặc định tốt, bạn bắt đầu sử dụng loại hoạt động và được kiểm tra tốt; sau đó bạn có thể sửa đổi các phần cần sửa đổi.

■ href Phiên bản Nếu bạn thêm một phương thức vào loại cơ sở, loại dẫn xuất kế thừa phương thức mới, bạn bắt đầu sử dụng một loại hoạt động và mã nguồn của người dùng thậm chí không phải biên dịch lại. Thêm một thành viên mới vào một giao diện buộc người kế thừa giao diện phải thay đổi mã nguồn và biên dịch lại.


1
@AbdullahShoaib là một và bất cứ ai có thể làm nhưng không thể làm, có một sự khác biệt ở đây. Đây là lý do cơ bản, chúng ta cần giao diện. hành vi có thể làm cũng là một phần của abstract class.
trao đổi quá mức

10

Một giao diện xác định hợp đồng cho một dịch vụ hoặc bộ dịch vụ. Chúng cung cấp tính đa hình theo chiều ngang trong đó hai lớp hoàn toàn không liên quan có thể thực hiện cùng một giao diện nhưng được sử dụng thay thế cho nhau như một tham số của loại giao diện mà chúng thực hiện, vì cả hai lớp đã hứa sẽ đáp ứng tập hợp các dịch vụ được xác định bởi giao diện. Các giao diện cung cấp không có chi tiết thực hiện.

Một lớp trừu tượng định nghĩa một cấu trúc cơ sở cho các lớp con của nó và thực hiện một phần tùy chọn. Các lớp trừu tượng cung cấp tính đa hình theo chiều dọc, nhưng theo hướng, trong đó bất kỳ lớp nào kế thừa lớp trừu tượng có thể được coi là một thể hiện của lớp trừu tượng đó nhưng không phải là cách khác. Các lớp trừu tượng có thể và thường không chứa các chi tiết triển khai, nhưng không thể tự khởi tạo - chỉ các lớp con của chúng có thể được "làm mới".

C # cũng cho phép kế thừa giao diện, làm phiền bạn.


1
Sử dụng các thuật ngữ ngangdọc làm cho nó rất rõ ràng để tưởng tượng sự khác biệt.
Vô cực

10

Hầu hết các câu trả lời tập trung vào sự khác biệt về kỹ thuật giữa Lớp trừu tượng và Giao diện, nhưng về mặt kỹ thuật, giao diện về cơ bản là một loại lớp trừu tượng (không có dữ liệu hoặc thực hiện), tôi nghĩ rằng sự khác biệt về khái niệm thú vị hơn nhiều, và đó có thể là những gì Những người phỏng vấn là sau.

Một giao diện là một thỏa thuận . Nó chỉ định: "đây là cách chúng ta sẽ nói chuyện với nhau". Nó không thể có bất kỳ triển khai nào vì nó không được phép thực hiện. Đó là một hợp đồng. Nó giống như các .htệp tiêu đề trong C.

Một lớp trừu tượng là một thực hiện không đầy đủ . Một lớp có thể hoặc không thể thực hiện một giao diện và một lớp trừu tượng không phải thực hiện nó hoàn toàn. Một lớp trừu tượng mà không có bất kỳ triển khai nào là loại vô dụng, nhưng hoàn toàn hợp pháp.

Về cơ bản bất kỳ lớp nào, trừu tượng hay không, là về nó gì , trong khi một giao diện là về cách bạn sử dụng nó . Ví dụ: Animalcó thể là một lớp trừu tượng thực hiện một số chức năng trao đổi chất cơ bản và chỉ định các phương pháp trừu tượng để thở và vận động mà không thực hiện, bởi vì nó không biết liệu nó nên thở qua mang hay phổi, và liệu nó có bay, bơi, đi bộ hay không bò Mountmặt khác, có thể là một Giao diện, xác định rằng bạn có thể cưỡi động vật, mà không cần biết đó là loại động vật nào (hoặc liệu đó có phải là động vật không!).

Thực tế là đằng sau hậu trường, một giao diện về cơ bản là một lớp trừu tượng chỉ có các phương thức trừu tượng, không thành vấn đề. Về mặt khái niệm, họ điền vào các vai trò hoàn toàn khác nhau.


10

Như bạn có thể có kiến ​​thức lý thuyết từ các chuyên gia, tôi không dành nhiều từ để lặp lại tất cả những điều ở đây, thay vào đó hãy để tôi giải thích với một ví dụ đơn giản nơi chúng ta có thể sử dụng / không thể sử dụng InterfaceAbstract class.

Hãy xem xét bạn đang thiết kế một ứng dụng để liệt kê tất cả các tính năng của Ô tô. Ở những điểm khác nhau, bạn cần có sự kế thừa chung, vì một số thuộc tính như DigitalFuelMeter, Điều hòa nhiệt độ, Điều chỉnh chỗ ngồi, vv là phổ biến cho tất cả các xe. Tương tự như vậy, chúng ta chỉ cần kế thừa cho một số lớp vì một số thuộc tính như hệ thống Phanh (ABS, EBD) chỉ áp dụng cho một số xe.

Lớp dưới đây hoạt động như một lớp cơ sở cho tất cả các xe:

public class Cars
{
    public string DigitalFuelMeter()
    {
        return "I have DigitalFuelMeter";
    }

    public string AirCondition()
    {
        return "I have AC";
    }

    public string SeatAdjust()
    {
        return "I can Adjust seat";
    }
}

Hãy xem xét chúng tôi có một lớp riêng cho mỗi chiếc xe.

public class Alto : Cars
{
    // Have all the features of Car class    
}

public class Verna : Cars
{
    // Have all the features of Car class + Car need to inherit ABS as the Braking technology feature which is not in Cars        
}

public class Cruze : Cars
{
    // Have all the features of Car class + Car need to inherit EBD as the Braking technology feature which is not in Cars        
}

Hãy xem xét chúng ta cần một phương pháp để kế thừa công nghệ Phanh cho những chiếc xe Verna và Cruze (không áp dụng cho Alto). Mặc dù cả hai đều sử dụng công nghệ phanh, "công nghệ" này lại khác. Vì vậy, chúng tôi đang tạo một lớp trừu tượng trong đó phương thức sẽ được khai báo là Trừu tượng và nó nên được thực hiện trong các lớp con của nó.

public abstract class Brake
{
    public abstract string GetBrakeTechnology();
}

Bây giờ chúng tôi đang cố gắng kế thừa từ lớp trừu tượng này và loại hệ thống phanh được triển khai trong Verna và Cruze:

public class Verna : Cars,Brake
{
    public override string GetBrakeTechnology()
    {
        return "I use ABS system for braking";
    }       
}

public class Cruze : Cars,Brake
{
    public override string GetBrakeTechnology()
    {
       return "I use EBD system for braking";
    }         
}

Xem vấn đề trong hai lớp trên? Chúng kế thừa từ nhiều lớp mà C # .Net không cho phép mặc dù phương thức này được triển khai ở trẻ em. Ở đây có sự cần thiết của Giao diện.

interface IBrakeTechnology
{
    string GetBrakeTechnology();
}

Và việc thực hiện được đưa ra dưới đây:

public class Verna : Cars, IBrakeTechnology
{
    public string GetBrakeTechnology()
    {
        return "I use ABS system for braking";
    }
}

public class Cruze : Cars, IBrakeTechnology
{
   public string GetBrakeTechnology()
   {
       return "I use EBD system for braking";
   }        
}

Bây giờ Verna và Cruze có thể đạt được nhiều sự kế thừa với các công nghệ phanh riêng với sự trợ giúp của Giao diện.


4
Đây là một trong những giải thích tốt nhất vì các ví dụ.
Adam Mendoza

2
Điều này có ý nghĩa với tôi mà không làm hỏng não. Tôi chỉ cố gắng đưa ra một ví dụ về xe hơi cho các học sinh của mình. Cảm ơn đã dành thời gian để đặt điều này cùng nhau.
tazboy

9

Giao diện là cách trọng lượng nhẹ để thực thi một hành vi cụ thể. Đó là một cách để nghĩ.


8

Những câu trả lời này quá dài.

  • Giao diện là để xác định hành vi.

  • Các lớp trừu tượng là để xác định một điều chính nó, bao gồm các hành vi của nó. Đó là lý do tại sao đôi khi chúng ta tạo ra một lớp trừu tượng với một số thuộc tính bổ sung kế thừa giao diện.

Điều này cũng giải thích tại sao Java chỉ hỗ trợ kế thừa duy nhất cho các lớp nhưng không hạn chế các giao diện. Bởi vì một vật cụ thể không thể là những thứ khác nhau, nhưng nó có thể có những hành vi khác nhau.


7

1) Một giao diện có thể được xem như là một lớp Trừu tượng thuần túy, giống nhau, nhưng mặc dù vậy, nó không giống nhau để thực hiện một giao diện và kế thừa từ một lớp trừu tượng. Khi bạn kế thừa từ lớp trừu tượng thuần túy này, bạn đang xác định một hệ thống phân cấp -> kế thừa, nếu bạn triển khai giao diện mà bạn không và bạn có thể thực hiện nhiều giao diện như bạn muốn, nhưng bạn chỉ có thể kế thừa từ một lớp.

2) Bạn có thể định nghĩa một thuộc tính trong một giao diện, vì vậy lớp thực hiện giao diện đó phải có thuộc tính đó.

Ví dụ:

  public interface IVariable
  {
      string name {get; set;}
  }

Lớp thực hiện giao diện đó phải có một thuộc tính như thế.


7

Mặc dù câu hỏi này khá cũ, tôi muốn thêm một điểm khác có lợi cho giao diện:

Các giao diện có thể được tiêm bằng cách sử dụng bất kỳ công cụ Dependency Injection nào trong đó như tiêm lớp trừu tượng được hỗ trợ bởi rất ít.


1
Tôi tin rằng bạn có nghĩa là một công cụ DI có thể tạo ra một lớp thực hiện giao diện. Một số công cụ như vậy cũng có thể tiêm các lớp có nguồn gốc từ một lớp trừu tượng, hoặc bạn đang nói rằng điều đó là không thể?
John Saunders

6

Từ một câu trả lời khác của tôi , chủ yếu là giải quyết khi nào nên sử dụng cái này so với cái kia:

Theo kinh nghiệm của tôi, các giao diện được sử dụng tốt nhất khi bạn có một vài lớp mà mỗi lớp cần đáp ứng với cùng một phương thức hoặc phương thức để chúng có thể được sử dụng thay thế cho nhau bởi mã khác sẽ được viết trên giao diện chung của các lớp đó. Việc sử dụng giao diện tốt nhất là khi giao thức quan trọng nhưng logic cơ bản có thể khác nhau đối với mỗi lớp. Nếu bạn muốn sao chép logic, thay vào đó hãy xem xét các lớp trừu tượng hoặc kế thừa lớp tiêu chuẩn.


6

Các loại giao diện so với các lớp cơ sở trừu tượng

Được chuyển thể từ Pro C # 5.0 và sách .NET 4.5 Framework .

Kiểu giao diện có thể rất giống với một lớp cơ sở trừu tượng. Hãy nhớ lại rằng khi một lớp được đánh dấu là trừu tượng, nó có thể định nghĩa bất kỳ số lượng thành viên trừu tượng nào để cung cấp giao diện đa hình cho tất cả các kiểu dẫn xuất. Tuy nhiên, ngay cả khi một lớp định nghĩa một tập hợp các thành viên trừu tượng, bạn cũng có thể tự do định nghĩa bất kỳ số lượng hàm tạo, dữ liệu trường, các thành viên không thể loại trừ (có triển khai), v.v. Mặt khác, các giao diện chỉ chứa các định nghĩa thành viên trừu tượng. Giao diện đa hình được thiết lập bởi một lớp cha trừu tượng chịu một hạn chế chính trong đó chỉ các kiểu dẫn xuất hỗ trợ các thành viên được xác định bởi cha mẹ trừu tượng. Tuy nhiên, trong các hệ thống phần mềm lớn hơn, việc phát triển nhiều hệ thống phân cấp lớp không có cha mẹ chung ngoài System.Object là điều rất phổ biến. Do các thành viên trừu tượng trong một lớp cơ sở trừu tượng chỉ áp dụng cho các kiểu dẫn xuất, chúng ta không có cách nào để cấu hình các kiểu trong các cấu trúc phân cấp khác nhau để hỗ trợ cùng một giao diện đa hình. Bằng cách ví dụ, giả sử bạn đã định nghĩa lớp trừu tượng sau:

public abstract class CloneableType
{
// Only derived types can support this
// "polymorphic interface." Classes in other
// hierarchies have no access to this abstract
// member.
   public abstract object Clone();
}

Với định nghĩa này, chỉ những thành viên mở rộng ClonizableType mới có thể hỗ trợ phương thức Clone (). Nếu bạn tạo một nhóm các lớp mới không mở rộng lớp cơ sở này, bạn không thể có được giao diện đa hình này. Ngoài ra, bạn có thể nhớ lại rằng C # không hỗ trợ nhiều kế thừa cho các lớp. Do đó, nếu bạn muốn tạo MiniVan - Xe hơi và - ClonizableType, bạn không thể làm như vậy:

// Nope! Multiple inheritance is not possible in C#
// for classes.
public class MiniVan : Car, CloneableType
{
}

Như bạn đoán, các loại giao diện đến để giải cứu. Sau khi một giao diện đã được xác định, nó có thể được thực hiện bởi bất kỳ lớp hoặc cấu trúc nào, trong bất kỳ hệ thống phân cấp nào, trong bất kỳ không gian tên hoặc bất kỳ hội đồng nào (được viết bằng bất kỳ ngôn ngữ lập trình .NET nào). Như bạn có thể thấy, các giao diện rất đa hình. Hãy xem xét giao diện .NET tiêu chuẩn có tên IClonizable, được xác định trong không gian tên Hệ thống. Giao diện này định nghĩa một phương thức duy nhất có tên Clone ():

public interface ICloneable
{
object Clone();
}

6

Câu trả lời cho câu hỏi thứ hai: publicbiến quy định tại interfacestatic finaltheo mặc định trong khi publicbiến trong abstractlớp là một biến số ví dụ.


6

Để chắc chắn điều quan trọng là phải hiểu hành vi của giao diện và lớp trừu tượng trong OOP (và cách ngôn ngữ xử lý chúng), nhưng tôi nghĩ điều quan trọng là phải hiểu chính xác ý nghĩa của từng thuật ngữ. Bạn có thể tưởng tượng iflệnh không hoạt động chính xác như ý nghĩa của thuật ngữ này không? Ngoài ra, trên thực tế, một số ngôn ngữ đang giảm, thậm chí nhiều hơn, sự khác biệt giữa giao diện và trừu tượng ... nếu tình cờ một ngày hai thuật ngữ hoạt động gần như giống hệt nhau, ít nhất bạn có thể tự xác định vị trí của chúng (và tại sao) được dùng cho.

Nếu bạn đọc qua một số từ điển và các phông chữ khác, bạn có thể tìm thấy các ý nghĩa khác nhau cho cùng một thuật ngữ nhưng có một số định nghĩa chung. Tôi nghĩ rằng hai ý nghĩa tôi tìm thấy trong trang web này là thực sự, thực sự tốt và phù hợp.

Giao diện:

Một điều hoặc hoàn cảnh cho phép các yếu tố riêng biệt và đôi khi không tương thích phối hợp hiệu quả.

Trừu tượng:

Một cái gì đó tập trung vào chính nó những phẩm chất thiết yếu của bất cứ điều gì rộng lớn hơn hoặc tổng quát hơn, hoặc của một số điều; Bản chất.

Thí dụ:

Bạn đã mua một chiếc xe hơi và nó cần nhiên liệu.

nhập mô tả hình ảnh ở đây

Mô hình xe hơi của bạn là XYZ, thuộc thể loại ABC, vì vậy nó là một chiếc xe cụ thể, một ví dụ cụ thể của một chiếc xe hơi. Một chiếc xe không phải là một đối tượng thực sự. Trong thực tế, nó là một bộ trừu tượng của các tiêu chuẩn (phẩm chất) để tạo ra một đối tượng cụ thể. Nói tóm lại, Car là một lớp trừu tượng , nó là "thứ gì đó tập trung vào chính nó những phẩm chất thiết yếu của bất cứ thứ gì rộng lớn hơn hoặc tổng quát hơn" .

Nhiên liệu duy nhất phù hợp với đặc điểm kỹ thuật của xe nên được sử dụng để đổ đầy bình xăng. Trong thực tế, không có gì để hạn chế bạn đặt bất kỳ nhiên liệu nào nhưng động cơ sẽ chỉ hoạt động đúng với nhiên liệu được chỉ định, vì vậy tốt hơn là nên làm theo yêu cầu của nó. Các yêu cầu nói rằng nó chấp nhận, như những chiếc xe khác cùng thể loại ABC, một bộ nhiên liệu tiêu chuẩn.

Theo quan điểm hướng đối tượng, nhiên liệu cho thể loại ABCkhông nên được khai báo là một lớp vì không có nhiên liệu cụ thể cho một thể loại xe cụ thể ngoài kia. Mặc dù xe của bạn có thể chấp nhận một loại nhiên liệu trừu tượng hoặc VehicularFuel, bạn phải nhớ rằng chỉ một số nhiên liệu xe cộ hiện có của bạn đáp ứng các đặc điểm kỹ thuật, những loại thực hiện các yêu cầu trong hướng dẫn sử dụng xe của bạn. Nói tóm lại, họ nên thực hiện giao diện ABCGenreFuel , "... cho phép các yếu tố riêng biệt và đôi khi không tương thích để phối hợp hiệu quả" .

Phụ lục

Ngoài ra, tôi nghĩ bạn nên ghi nhớ ý nghĩa của lớp thuật ngữ, đó là (từ cùng một trang web đã đề cập trước đó):

Lớp học:

Một số người hoặc những thứ được coi là thành lập một nhóm vì lý do thuộc tính, đặc điểm, phẩm chất hoặc đặc điểm chung; Tốt bụng;

Theo cách này, một lớp (hoặc lớp trừu tượng) không nên chỉ đại diện cho các thuộc tính chung (như giao diện), mà là một loại nhóm có thuộc tính chung. Một giao diện không cần phải đại diện cho một loại. Nó phải đại diện cho các thuộc tính phổ biến. Theo cách này, tôi nghĩ rằng các lớp và các lớp trừu tượng có thể được sử dụng để đại diện cho những thứ không nên thay đổi các khía cạnh của nó thường xuyên, giống như một con người là Động vật có vú, bởi vì nó đại diện cho một số loại. Các loại không nên thay đổi bản thân thường xuyên.


1
quá nhiều lông tơ, đừng làm cho nó trở nên khó hiểu với mọi người hơn nó có thể.
ganjeii

5

Từ góc nhìn mã hóa

Giao diện có thể thay thế Lớp trừu tượng nếu Lớp trừu tượng chỉ có các phương thức trừu tượng. Mặt khác, việc thay đổi lớp Trừu tượng thành giao diện có nghĩa là bạn sẽ mất khả năng sử dụng lại mã mà Tính kế thừa cung cấp.

Từ quan điểm thiết kế

Giữ nó dưới dạng Lớp trừu tượng nếu đó là mối quan hệ "Là một" và bạn cần một tập hợp con hoặc tất cả các chức năng. Giữ nó làm Giao diện nếu đó là mối quan hệ "Nên làm".

Quyết định những gì bạn cần: chỉ cần thực thi chính sách, hoặc mã tái sử dụng và chính sách.


3

Một số khác biệt khác:

Các lớp trừu tượng có thể có các phương thức tĩnh, thuộc tính, trường v.v. và toán tử, giao diện không thể. Toán tử truyền cho phép truyền tới / từ lớp trừu tượng nhưng không cho phép truyền tới / từ giao diện.

Rất nhiều bạn có thể tự mình sử dụng lớp trừu tượng ngay cả khi nó không bao giờ được triển khai (thông qua các thành viên tĩnh) và bạn không thể tự mình sử dụng giao diện theo bất kỳ cách nào.


trong Java, giao diện có thể có biến thành viên nhưng theo mặc định, chúng trở thành tĩnh công khai .. giao diện cũng có thể có các trường tĩnh
Jitendra Vispute

Có giao diện có thể có các trường tĩnh. Giao diện BUT không thể có các phương thức tĩnh.
một người học
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.