Interface - Giao diên trong C#

 

1. Định nghĩa interface (giao diện) 

Giao diện là ràng buộc, giao ước đảm bảo cho các lớp hay các cấu trúc sẽ thực hiện một điều gì đó. Khi một lớp thực thi một giao diện, thì lớp này báo cho các thành phần client biết rằng lớp này có hỗ trợ các phương thức, thuộc tính, sự kiện và các chỉ mục khai báo trong giao diện. 

Một giao diện thì giống như một lớp chỉ chứa các phương thức trừu tượng. Một lớp trừu tượng được dùng làm lớp cơ sở cho một họ các lớp dẫn xuất từ nó. Trong khi giao diện là sự trộn lẫn với các cây kế thừa khác.

Tuy nhiên bạn phải hiểu là giao diện không phải là lớp.

Sau đây sẽ giới thiệu với bạn cách định nghĩa và thực thi một giao diện

Cú pháp để định nghĩa một giao diện như sau:

 

[thuộc tính] [phạm vi truy cập] interface <tên giao diện> [: danh sách cơ sở]
 {

  /* phần thân giao diện */

 }

 

Phần thuộc tính chúng ta chưa đề cập tới các bạn hãy lưu ý đến phần phạm vi truy cập bao gồm public, private, protected, internal, và protected internal đã được nói đến. Theo sau từ khóa interface là tên của giao diện. Thông thường tên của giao diện được bắt đầu với từ I hoa (điều này không bắt buộc nhưng việc đặt tên như vậy rất rõ ràng và dễ hiểu, tránh nhầm lẫn với các thành phần khác).

Danh sách cơ sở là danh sách các giao diện mà giao diện này mở rộng, phần này sẽ được trình bày trong phần thực thi nhiều giao diện. Phần thân của giao diện chính là phần thực thi giao diện.

2. Thực thi giao diện

Giả sử chúng ta muốn tạo một giao diện nhằm mô tả những phương thức và thuộc tính của một lớp cần thiết để lưu trữ và truy cập từ một cơ sở dữ liệu hay các thành phần lưu trữ dữ liệu khác như là một tập tin. Chúng ta quyết định gọi giao diện này là IStorage. Trong giao diện này chúng ta xác nhận hai phương thức: Read() và Write(), khai báo này sẽ được xuất hiện trong phần thân của giao diện như sau: 

 

interface IStorable
{
    void Read();
    void Write(object);
}

 

Mục đích của một giao diện là để định nghĩa những khả năng mà chúng ta muốn có trong một lớp. Ví dụ, chúng ta có thể tạo một lớp tên là Document, lớp này lưu trữ các dữ liệu trong cơ sở dữ liệu, do đó chúng ta quyết định lớp này này thực thi giao diện IStorable. Để làm được điều này, chúng ta sử dụng cú pháp giống như việc tạo một lớp mới Document được thừa kế từ IStorable bằng dùng dấu hai chấm (:) và theo sau là tên giao diện:

 

public class Document : IStorable
{
    public void Read()
    {
        // ...
    }
    public void Write()
    {
        //...
    }
}

 

Dưới đây là code minh họa việc thực thi giao diện:

 

using System;

// khai báo giao diện
interface IStorable
{
    // giao diện không khai báo bổ sung truy cập
    // phương thức là public và không thực thi (chỉ khai báo)
    void Read();
    void Write(object obj);
    int Status
    {
        get;
        set;
    }
}

// tạo một lớp thực thi giao diện IStorable
public class Document : IStorable
{
    public Document(string s)
    {
        Console.WriteLine("Creating document with: {0}", s);
    }

    // thực thi phương thức Read()
    public void Read()
    {
        Console.WriteLine("Implement the Read Method for IStorable");
    }

    // thực thi phương thức Write
    public void Write(object o)
    {
        Console.WriteLine("Impleting the Write Method for IStorable");
    }

    // thực thi thuộc tính
    public int Status
    {
        get
        {
            return status;
        }
        set
        {
            status = value;
        }
    }

    // khai báo trường dữ liệu status
    private int status = 0;
}

public class Tester
{
    static void Main()
    {
        // khởi tạo đối tượng Document
        Document doc = new Document("Test Document");
        doc.Status = -1;
        doc.Read();
        Console.WriteLine("Document Status: {0}", doc.Status);

        // khởi gán một giao diện
        IStorable isDoc = (IStorable)doc;
        isDoc.Status = 0;
        isDoc.Read();

        Console.WriteLine("IStorable Status: {0}", isDoc.Status);
        Console.ReadLine();
    }
}

 

3. Thực thi nhiều giao diện

Trong ngôn ngữ C# cho phép chúng ta thực thi nhiều hơn một giao di��n. Ví dụ, nếu lớp Document có thể được lưu trữ và dữ liệu cũng được nén. Chúng ta có thể chọn thực thi cả hai giao diện IStorable và ICompressible. Như vậy chúng ta phải thay đổi phần khai báo trong danh sách cơ sở để chỉ ra rằng cả hai giao diện điều được thực thi, sử dụng dấu phẩy (,) để phân cách giữa hai giao diện:

 

public class Document : IStorable, ICompressible

 

Khi đó lớp Document phải thực hiện đầy đủ các method được khai báo trong ICompressible.

4. Mở rộng giao diện

C# cung cấp chức năng cho chúng ta mở rộng một giao diện đã có bằng cách thêm các phương thức và các thành viên hay bổ sung cách làm việc cho các thành viên. Ví dụ, chúng ta có thể mở rộng giao diện ICompressible với một giao diện mới là ILoggedCompressible. Giao diện mới này mở rộng giao diện cũ bằng cách thêm phương thức ghi log các dữ liệu đã lưu:

 

interface ILoggedCompressible : ICompressible
{
    void LogSavedBytes();
}

 

5. Kết hợp giao diện

Một cách tương tự, chúng ta có thể tạo giao diện mới bằng cách kết hợp các giao diện cũ và ta có thể thêm các phương thức hay các thuộc tính cho giao diện mới. Ví dụ, chúng ta quyết định tạo một giao diện IStorableCompressible. Giao diện mới này sẽ kết hợp những phương thức của cả hai giao diện và cũng thêm vào một phương thức mới để lưu trữ kích thước nguyên thuỷ của các dữ liệu trước khi nén:

 

interface IStorableCompressible : IStoreable, ILoggedCompressible
{
    void LogOriginalSize();
}

 

Các bạn đã được làm quen với một khái niệm nữa trong C# đó là giao diện (interface). Cách định nghĩa và thực thi một interface, các thực thi nhiều interface, mở rộng và kết hợp các interface.

Nguồn: http://vubka.blogspot.com/2010/04/interface.html

 

SỰ KHÁC BIỆT GIỮA LỚP TRỪU TƯỢNG ABSTRACT VÀ GIAO DIỆN INTERFACE

 

Đối với lập trình C# hay lập trình hướng đối tượng nói chung, vấn đề kế thừa sẽ đem lại nhiều phiền toái nếu bạn chưa nắm rõ về vấn đề này. Vậy thì sự khác biệt giữa lớp abstract interface ở chỗ nào?

Một lớp trừu tượng thì không có thể hiện nghĩa là ta không thể khởi tạo nó bằng toán tử new, và một phương thức trong nó là abstract thì chỉ được đưa ra định nghĩa (khai báo) mà không được thực thi và nó sẽ được overriden lại trong các lớp con kế thừa. Và trong lớp mà tồn tại phương thức abstract thì lớp đó cũng được định nghĩa abstract.

Đối với giao diện thì khác hoàn toàn với lớp trừu tượng, nó định nghĩa một cách cứng nhắc các phương thức và thuộc tính trong chúng nghĩa là không cho phép ta thực thi bất kỳ một đoạn mã nào. Và tất cả các thành viên trong nó đều được định nghĩa công khai (public). Một cách tổng quan về giao diện: Giao diện là ràng buộc, giao ước đảm bảo cho các lớp hay các cấu trúc sẽ thực hiện một điều gì đó. Khi một lớp thực thi một giao diện, thì lớp này báo cho các thành phần client biết rằng lớp này có hỗ trợ các phương thức, thuộc tính, sự kiện và các chỉ mục khai báo trong giao diện.

Một số lưu ý khi sử dụng abstract hay interface

Một class chỉ có thể kế thừa từ một abstract class, nhưng có thể kế thừa nhiều interface.

Trong Interface chỉ có thể khai báo các fields, methods, mà không được hiện thực nó. Còn đối với abstract thì dùng các biến, hiện thực cách methods.

Các fields, methods trong interace đều là public và bắt buộc các class kế thừa phải cài đặt nó (abstract). Trong abstract class thì có các fields, methods có thể là private, internal, public, protected và có thể là abstract hoặc non-abstract.

Interface dùng để gom các hành động cần được hiện thực, các khả năng của một đối tượng, còn abstract class cho các lớp thừa kế cùng 1 loại, tính chất hay trạng thái.

Abstract class có tốc độ thực thi nhanh hơn interface.

Thêm 1 tính năng mới vào interface sẽ phá vỡ toàn bộ các lớp hiện thực, còn abstract thì không.

Ví dụ về interface, các thành viên của interface phải được thực thi trong các lớp mà kế thừa từ nó

 

public interface IPlayer
{
    string Name {get; set;}
    Player Actor { get; set; } 
    Bitmap Image { get; set; }
}

 

Ví dụ dưới đây khai báo một lớp abstract có các thành viên trong nó là abstract và non-abstract, và được thực thi trong lớp con là Faculty

 

abstract class Employee
{
    protected string m_str_department;
    protected double m_db_salary;
    protected int m_i_dateHired;
    public string Department
    {
        get { return m_str_department; }
        set { m_str_department = value; }
    }
    public double Salary
    {
        get { return m_db_salary; }
        set { m_db_salary = value; }
    }
    public int DateHired
    {
        get { return m_i_dateHired; }
        set { m_i_dateHired = value; }
    }
    public override string ToString()
    {
        return "Employee: " + m_str_name
        + "\nEmail: " + m_str_email;
    }
    public abstract double CalculateBonus();
    public abstract int CalculateVacation();
}

class Faculty : Employee
{
    string m_str_rank;
    double m_db_hours;
    public override double CalculateBonus()
    {
        return 1000 + 0.05 * m_db_salary;
    }
    public override int CalculateVacation()
    {
        if (m_i_dateHired > 3)
        {
            if (m_str_rank == "Senior Lecture")
                return 6;
            return 5;
        }
        if (m_str_rank == "Senior Lecture")
            return 5;
        return 4;
    }
}

Nguồn: http://vubka.blogspot.com/2010/08/su-khac-biet-giua-lop-truu-tuong.html

 

 

và một bài viết khác cũng khá dễ hiểu

Interface & Abstract class !

Thường khi mới tiếp xúc với Interface Abstract Class sẽ có nhiều câu hỏi hoàn toàn không ngớ ngẩn rằng "Dùng Interface để làm gì? Trong khi chỉ thừa kế được mỗi cái tên Method!".

Nói kế thừa thì chính xác chỉ có Abstract mới là kế thừa thực sự, Interface là Implement, not Inherit. Trong Abstract, chúng ta xây dựng nên lớp Base với đầy đủ các thành phần của một Class, bao gồm các Property, Method, riêng các Method Abstract thì là No Body ! Cái No Body này giống với Interface, Interface chỉ gồm tên của các Method, nó hoàn toàn No Body, không có gì cả. 

Ví dụ :

interface IGeometry
{
    bool IsEmpty();
    bool Overlaps(Geometry geom);
    Geometry Boundary();
}
abstract class Geometry : IGeometry
{
    protected string _Id;
    public virtual string GetId()
    {
        return _Id;
    }
    public virtual bool Overlaps(Geometry geom)
    {
        return SharpMap.Geometries.SpatialRelations.Overlaps(this, geom);
    }
    public abstract bool IsEmpty();
    public abstract Geometry Boundary();
}

Trong ví dụ trên, IGeometry là một Interface bao gồm 3 prototype – không được định nghĩa thân hàm. Geometry là một Abstract Class  kế thừa luôn  IGeometry Interface. Geometry  có một property kiểu string là _Id, một hàm trả về kiểu string là GetId để trả về giá trị _Id, các thành phần này được thiết kế dùng cho việc kế thừa sau này của các lớp khác. Đồng thời, Geometry bắt buộc chứa 3 hàm đã được mô tả trong IGeometry Interface là Overlap, IsEmpty và Boundary. 

Điều gì làm nên đặc trưng của một Abstract Class, đó chính là 3 hàm abstract không được định nghĩa thân hàm. Các hàm này sẽ được định nghĩa trong các lớp dẫn xuất có  kế thừa  từ Geometry. Lại thêm một câu hỏi nữa, việc định nghĩa các hàm Abstract có bị bắt buộc trong lớp dẫn xuất không, xin thưa rằng bắt buộc! 

Nhìn một cách nào đó, bạn có thể thấy rằng, Interface giống như những câu lạc bộ, và Abstract class là một ông bố trong gia đình. 

Một câu lạc bộ luôn luôn có một bộ quy tắc hay nôi qui mà mọi thành viên luôn phải tuân theo. Một ông bố trong gia đình thì khác, ông có tài sản mà con cháu có thể kế thừa, ông cũng có những qui định trong di chúc – ai là người được kế thừa tài sản của ông! 

Bạn có thể tham gia cùng lúc nhiều câu lạc bộ như việc một Class "kế thừa" (Implement) nhiều Interface. Một khi đã tham gia vào CLB nào, bạn phải tuân thủ tất cả các qui tắc của CLB đó, không quan tâm bạn là thành viên của bao nhiêu CLB. Đó là việc tại sao phải Implement đầy đủ các Interface member.

CLB không để lại tài sản cho các bạn, nhưng bố của bạn thì có, ông ấy cho bạn tài sản (không nếu ông ấy không thích Laughing) và cũng bắt bạn tuân theo các qui tắc – gia qui. Và một khi đã là con của người này thì bạn không thể nào là con của người khác giống như không thể kế thừa từ nhiều Abstract Class!

 Chú ý, đôi khi bạn không thực hiện vài qui định nào đó (có người yêu chẳng hạn), hãy nói với bố bạn, ông ấy sẽ đồng ý! C# cũng thế,lời xin phép là : throw new NotImplementedException();

Nguồn: http://nvhuan.wordpress.com/2010/01/19/interface-abstract-class/

Interface là cái gì vậy??? sài sao???

Interface được sử dụng rất nhiều trong phân tích thiết kế hướng đối tượng,
Khi một đối tượng hiện thực một interface thì nó sẽ phải hiện thực tất cả các thuộc tính và phương thức trong interface đó.
Điều này có ứng dụng là khi 2 đối tượng có quan hệ với nhau, chúng ta chỉ cần làm việc với interface của nó mà không cần biết cụ thể nó là đối tượng nào.
Đoạn code này minh họa điều đã nói: 

public interface IMyInterface
    {
        string Name { get; set; }
        void Print();
    }
    public class MyFace1 : IMyInterface
    {
        public string Name
        {
            get;
            set;
        }

        public void Print()
        {
            Console.WriteLine(Name);
        }
    }
    public class MyFace2 : IMyInterface
    {
        public string Name
        {
            get;
            set;
        }

        public void Print()
        {
            Console.WriteLine(Name);
        }
    }
    public class Implement
    {
        public void Run(IMyInterface face)
        {
            if (null != face)
            {
                face.Print();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyFace1 f1 = new MyFace1();
            f1.Name = "I'm face1";
            MyFace2 f2 = new MyFace2();
            f2.Name = "I'm face2";
            Implement imp = new Implement();
            imp.Run(f1);
            imp.Run(f2);
            Console.ReadKey();
        }
    }

Các bạn thấy rằng hàm Run trong lớp Implement không cần quan tâm đến đó là face1 hay face2 chỉ cần nó hiện thực IMyInterface là hàm Run có thể làm việc được.
interface còn nhiều ứng dụng, trong vấn đề trả lời cầu hỏi "dùng để làm gì" thì có 1 ví dụ như trên để bạn có thể mường tượng ra nó làm gì.
- Trong các hệ thống nhiều thành phần, mỗi phần được viết bởi nhiều nhóm phát triển khác nhau, interface có tác dụng là một bản yêu cầu để các nhóm khác hiện thực đúng chức năng mà interface yêu cầu, để nhóm khác không cần biết bạn viết gì, chỉ cần quan tâm bạn có những hàm, thuộc tính theo yêu cầu đã đặc tả là họ có thể làm việc được với nhau.
- Cách sử dụng interface cũng muôn vàn, các bạn nên hiểu về nó và khi đó áp dụng vào phân tích thiết kế hướng đối tượng tốt hơn.

 

Chôm từ: http://cione.com.vn/Questions/AnswerQuestion?Id=744&page=2&TypeSearch=-1