OOP – Interface vs Abstract class

Angry birdHiệ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 bird

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

YinYang’s Programming Blog

Advertisements

30 thoughts on “OOP – Interface vs Abstract class

  1. “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 abstract class được gọi là can-do (hoặc –able).”
    -> Hình như chỗ này bị nhầm, “một class khi hiện thực một interface được gọi là can-do (hoặc –able)” mới đúng.

    Phản hồi
      • Bạn ko thể đưa cho người dùng một công cụ có một chức năng lỗi (hoặc ko phù hợp) và bảo họ đừng sử dụng. Cách tốt nhất là khóa nó lại bằng sealed như bạn Án Bình Trọng.
        Đứng trên phương diện người phát hành một library thì điều này cần được tuân thủ chặt chẽ để tránh những sai sót đáng tiếc và ảnh hưởng tới logic của chương trình.
        Ngoài ra thì việc đặt sealed cũng góp phần tăng hiệu suất khi sử dụng các class đó.

  2. Cho mình hỏi một vấn đề về Interface.
    Ví dụ class CustomerService implements Interface IService.
    Lúc sử dụng CustomerService trong 1 class khác thì nên khai báo là:
    IService s = new CustomerService();
    chứ k nên dùng CustomerService s = new CustomerService();

    Phản hồi
  3. Tại sao phải khai báo như vậy?
    Mình chỉ biết Interface được sử dụng vì nó có tính đa kế thừa
    + khi muốn các class implement từ interface thực thi tất cả các phương thức được định nghĩa trong interface đó.

    Phản hồi
    • Việc viết theo cách này liên quan đến đặc tính đa hình của OOP và bạn sẽ thấy rõ tầm quan trọng của nó khi tìm hiểu về design pattern. Tức là thay vì xác định “kiểu” dữ liệu của một đối tượng/biến, bạn có thể tổng quát hơn bằng cách xác định “loại” dữ liệu của biến. Điều này giúp cho biến này có thể mang nhiều thuộc tính và behavior khác nhau giúp cho ứng dụng thêm linh hoạt.

      Phản hồi
  4. Bạn nên dùng từ khóa var để khai báo. VD: var s = new CustomerService();
    Khi bạn khai báo 1 function A, nếu bạn sử dụng A(List list) thì bạn bắt buộc phải truyền kiểu list. Còn nếu bạn khai báo A(IENumerable list) thì bạn có thể truyền vào Queryable hoặc List đều được, hàm của bạn sẽ linh động hơn. Chương trình sẽ tự xác định kiểu thích hợp khi thực thi hàm.

    Phản hồi
  5. Bài viết rất sắc sảo và tường minh, tính từ đoạn có hình ảnh minh họa!
    Các bài viết khác thường quá tập trung vào việc định nghĩa chúng là gì (what) – ai mà thèm quan tâm chứ, nhưng lại ko giải thích được dùng chúng như thế nào (how). Nhưng bạn đã làm được ở phần nửa cuối bài viết 🙂
    Giá như expert nào cũng có thể viết ngắn gọn, xúc tích thế này, newbie sẽ tiết kiệm được rất nhiều thời gian và công sức!

    Phản hồi
  6. Chào anh, trong công ty e có một anh đã nói cách sử dụng interface là để cung cấp các hàm cho phép người dùng sử dụng hàm đó mà không cần biết hàm đó được implement như thế nào. Như vậy là đúng hay sai a?

    Phản hồi
  7. Pingback: Phân biệt Interface và Abstract class | quanglnt's blog

  8. Pingback: [Hướng dẫn]Hướng đối tượng trong PHP: interface và asbtract class | SonHa's Blog

  9. Interface: Liên quan đến operate.
    Abstract class: Liên hệ đến xây dựng và khởi tạo lớp.
    Theo mình nghỉ, đối tượng được xây dựng theo trình tự
    Abstract class -> Base class + Interface – > Object

    Phản hồi

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s