[PHP] Interface/Abstract trong OOP

Standard

Bài tổng hợp từ nhiều nguồn trên Internet với mục đích tham khảo.

Phân biệt Interface và lớp Abstract trong OOP

Interface vs Abstract class in OOP

Hiện nay mặc dù OOP (Object Oriented Programming) đã rất phổ biến nhưng đa số vẫn còn khá mơ hồ trong việc phân biệt và định nghĩa hai khái niệm lớp Interface và Abstract. Bài viết này chúng ta sẽ tìm hiểu kỹ hơn về khái niệm và sự khác biệt giữa chúng, lưu ý ở đây là Abstract Class chứ không phải là Abstract Method nhé!

What is an Abstract Class?
Lớp trừu tượng đơn giản được xem như một class cha cho tất cả các Class có cùng bản chất. Do đó mỗi lớp dẫn xuất (lớp con) chỉ có thể kế thừa từ một lớp trừu tượng. Bên cạnh đó nó không cho phép tạo instance, nghĩa là sẽ không thể tạo được các đối tượng thuộc lớp đó.

What is an Interface?
Lớp này được xem như một mặt nạ cho tất cả các Class cùng cách thức hoạt động nhưng có thể khác nhau về bản chất. Từ đó lớp dẫn xuất có thể kế thừa từ nhiều lớp Interface để bổ sung đầy đủ cách thức hoạt động của mình (đa kế thừa – Multiple inheritance).

Ví dụ:
– Abstract class ConVat có các lớp con Chim, Ca.
– Abstract class MayMoc có các lớp con MayBay, Thuyen
– Interface: iBay, iBoi, iChay.
=> MayBay, Chim sẽ có cùng Interface là iBay. Rõ ràng mặc dù MayBay, Chim có cùng cách thức hoạt động là bay nhưng chúng khác nhau về bản chất.
=> MayBay cũng có interface là iChay nhưng Chim không thể nào kế thừa thêm abstract classMayMoc

Abstract Class vs Interface
Nhìn chung cả 2 đều là “bản thiết kế” cho các lớp dẫn xuất, do đó chúng chỉ chứa các khai báo Properties và Method mà không quan tâm bên trong thực hiện những gì. Nhưng cụ thể thì Abstract Class là “bản thiết kế” cho Class còn Interface là “bản thiết kế” cho Method.
(Ở đây s dùng C# làm ngôn ngữ cho ví dụ)

 

[codesyntax lang=”csharp”]

[/codesyntax]

 

Do được xem là bản thiết kế cho toàn Class, nên ngoài những khai báo Properties hoặc Method bắt buộc thì Abstarct class vẫn có thể chứa thêm các Method đã được triển khai hoặc các biến hằng. Ngược lại thì Interface hoàn toàn không thể làm được điều đó.

 

[codesyntax lang=”csharp”]

[/codesyntax]

 

Toàn bộ những Method và Properties trong Interface không cần khai báo Access modifier vì mặc định là Public. Abstract class thì phải bắt buộc khai báo (Public, Protected) và bắt buộc có từ khóa abstract trong các Method và Properties được khai báo trừu tượng. (Xem ví dụ 2)

Một điểm khác biệt nữa là ở lớp dẫn xuất của Interface class bắt buộc phải thực hiện toàn bộ những Method và Properties đã khai báo, ngược lại lớp dẫn xuất của Abstract class chỉ cần thực hiện những Method và Properties được khai báo trừu tượng (có từ khóa abstract)

[codesyntax lang=”csharp”]

[/codesyntax]

Ở PHP, sự phân biệt này càng rõ ràng hơn với từ khóa implement cho Interface vàextend cho Abstract class. Thực vậy, lớp dẫn xuất của Abstract class chỉ là mở rộng (extend) còn Interface thì buộc là thực hiện (implement) tất cả.


Đánh cho cái bây giờ. Đa kế thừa nào ở đây?

Mục đích của kế thừa là reuse lại code. Interface đâu có cho reuse lại code. Chính vì thế nó mới đi với từ
Code:
implements
. Các bác bên C++ và Python cứ lạm bàn thành và cố ép nó vào các kiểu của các bác ý.

Mục đích của interface là để tạo ra các ràng buộc về giao diện. Điều này là code lõi của của cái gọi là Design By Contract.

Người ta dùng nó làm gì và trong bối cảnh nào:

+ Bối cảnh thực tế: Có 3 ông khách vào một tòa nhà được bảo vệ nghiệm ngặt. Tòa nhà đó có 2 lớp kiểm tra:
– Kiểm tra hộ chiếu hay CMT
– Kiểm tra lịch hẹn

Vậy thì khi 3 ông khách vào, 3 ông sẽ phải thực hiện bắt buộc 2 thủ tục nó trên. Nghĩa là 3 ông dù có khác nhau thế nào, cao hay thấp đều phải có 2 khả năng này.

+ Mô tả tình huống trên bằng code thì sẽ có 3 class khác nhau nhưng chúng đều có 2 phương thức sau đây

— getPassport()
— getName()
Bây giờ chúng ta gói 2 phương thức nói trên vào một tên gọi chung là interface GuestRequirement

[codesyntax lang=”php”]
interface GuestRequirement
{
public function getPassport();
public function getName();
}[/codesyntax]
Interface này quy định về mặt hình thức các ràng buộc mà 3 lớp trên cần đáp ứng vì các ràng buộc đó sẽ được kiểm tra bởi lớp sẽ sử dụng nó.

Giả sử như lớp sử dụng (lớp của tòa nhà) có tên là SecurityStaff, nó sẽ sử dụng các lớp ràng buộc bởi interface như sau:

[codesyntax lang=”php”]

[/codesyntax]

Vậy lớp SecurityStaff không cần biết $guest là mẫu của class nào miễn là nó thỏa mãn các ràng buộc của GuestRequirement. 3 ông hay 5 ông, hay 10 ông nó mặc kệ.

Các bạn sẽ phải phân biệt cái gọi là

+ Reuse code: kế thừa lớp mẹ để không phải duplicate lại code.
+ Constrained by interface mà mục tiêu của nó là đảm bảo việc truyền message bên trong lớp sử dụng. Code bị duplicate là bình thường

Link: http://www.ddth.com/showthread.php/291056-PHP-Interface-trong-OOP#ixzz32QA8y4Lj


OOP – Interface vs Abstract class

Hiện nay mặc dù OOP đã rất phổ biến nhưng đa số vẫn còn khá mơ hồ trong việc phân biệt và định nghĩa hai khái niệm Interface và Abstract class. Có vẻ vấn đề này không được dạy rõ ràng ở trường, hoặc có thể các người dạy cũng chưa nắm rõ về nó. Ngoài ra, đây còn là một vấn đề cần giải quyết mà xác suất bạn nhận được khi đi phỏng vấn là khá cao.

Is-a và Can-do
Bỏ qua tất cả những phần về lý thuyết của việc tạo một abstract class và interface. Bạn không cần quan tâm nhiều đến việc abstract có thể khai báo những gì, hay interface có được phép định nghĩa nội dung phương thức hay không. Điểm cơ bản khi bạn được hỏi về sự khác biệt giữa chúng là gì? Đó chính là mục đích mà chúng được sử dụng:

– Abstract class: là một class cha cho tất cả các class có cùng bản chất. Bản chất ở đây được hiểu là kiểu, loại, nhiệm vụ của class. Hai class cùng hiện thực một interface có thể hoàn toàn khác nhau về bản chất.

– Interface: là một chức năng mà bạn có thể thêm và bất kì class nào. Từ chức năng ở đây không đồng nghĩa với phương thức (hoặc hàm). Interface có thể bao gồm nhiều hàm/phương thức và tất cả chúng cùng phục vụ cho một chức năng.

Vậy, bạn không nên nhầm lẫn khi nói về việc một class được implement hay extend. Nhiều người thường hay đồng nhất là không phân biệt hai từ này, nhưng chính chúng đã nói lên sự khác biệt giữa interface và abstract class. Bạn chỉ có thể thừa kế (extend) từ một class và chỉ có thể hiện thực (implement) các chức năng (interface) cho class của mình.

Theo cách ngắn gọn, quan hệ giữa một class khi thừa kế một abstract class được gọi là is-a, và một class khi hiện thực một interface được gọi là can-do (hoặc –able).

Hãy xem ví dụ sau, tôi có:

– Interface: Barkable, Runable, Flyable, Swimable.

– Abstract class Animal và các sub class: Bolt, AngryBird và Nemo.

– Abstract class Machine và các sub class: McQueen, Siddeley.

abstract-class-interface-oop

Như bạn thấy, mặc dù cả McQueen và Bolt đều được hiện thực interface Runable, nhưng chúng hoàn toàn thuộc hai loại khác nhau. Và tất nhiên một class có thể can-do nhiều thứ, ví dụ như Bolt có thể chạy và “bow wow”.

angry-bird-fly

Dùng Interface như một “bản thiết kế” của class?
Đây là một điều thường được dùng để trả lời cho hai câu hỏi:

– Interface được dùng để làm gì?

– Tại sao không thể định nghĩa phần thân cho các phương thức của interface.

Xét ở một mức độ nào đó điều này là hợp lý, nhưng như đã nói ở phần trên, nó chỉ được dùng để mô tả một “bản thiết kế” cho một chức năng của class. Nếu muốn tạo một bản thiết kế, hãy sử dụng abstract class. Một bản thiết kế tất nhiên sẽ có những thứ đã được dựng sẵn và có những thứ là abstract.

Một câu trả lời có thể lý giải phần nào câu hỏi thứ hai là việc cho phép định nghĩa thân phương thức trong các interface có thể khiến cho hiệu suất bị giảm sút. Nguyên nhân là việc tìm kiếm các phương thức sẽ diễn ra lâu hơn vì phải duyệt qua các interface, thay vì chỉ cần phải tìm trong class cha của nó.

angry-bird1

Về công dụng của interface, xét ở mức ứng dụng, các interface có thể được hiểu như các plugin hoặc thư viện/phần mềm third-party. Việc hiện thực một interface cho class cũng giống như cài thêm plugin cho một phần mềm vậy.

Bảng so sánh
Cuối cùng, cũng nên liệt kê các điểm khác biệt giữa hai khái niệm này để bạn có thể sử dụng được khi cần thiết. Các điểm khác biệt này có thể khác nhau tùy vào ngôn ngữ mà bạn sử dụng. Vì vậy bạn chỉ cần nhớ các điểm căn bản sau:

Interface Abstract class
Multiple inheritance Một class có thể hiện thực nhiều interface.(tạm coi là thừa kế) Không hỗ trợ đa thừa kế
Default implementation Không thể định nghĩa code xử lý, chỉ có thể khai báo. Có thể định nghĩa thân phương thức, property.
Access Modifiers Mọi phương thức, property đều mặc định là public. Có thể xác định modifier.
Adding functionality Mọi phương thức, property của interface cần được hiện thực trong class. Không cần thiết.
Fields and Constants Không

Theo: YinYang’s Programming Blog

Leave a Reply

Your email address will not be published. Required fields are marked *

+ 68 = 75