Lập trình C#

Giới thiệu interface trong lập trình C#

Giới thiệu interface trong lập trình C#
Được viết bởi Minh Hoàng

Series lập trình C#, ngôn ngữ lập trình hiện đại và mạnh mẽ.

– Nội dung của bài viết này mình sẽ trình bày về interface trong C#. Đây là khái niệm rất cơ bản trong lập trình hướng đối tượng nói chung và lập trình C# nói riêng.

– Nếu bạn nào đã tìm hiểu và làm việc với ngôn ngữ lập trình Java thì khái niệm interface hoàn toàn không xa lạ. Vậy interface là gì? Mục đích sử dụng của nó? Chúng ta sẽ cùng tìm hiểu trong bài viết này.

1. Dẫn nhập
1. Dẫn nhập

Ví dụ 1: Để dễ hình dung các bạn có thể liên tưởng đến con ếch, nó là loài lưỡng cư:

  • Vừa là động vật trên cạn.
  • Vừa là động vật có thể sống dưới nước.

Nên nó có thể “kế thừa” 2 lớp động vật này, nhưng trong C# chỉ hỗ trợ đơn thừa kế, mà không hỗ trợ đa thừa kế.

Ví dụ 2: Cách đánh giá kết quả của sinh viên tại các trường đại học và các trung tâm như trung tâm tiếng Anh, trung tâm Tin học,… là khác nhau, chẳng hạn như đối với loại Giỏi thì:

  • Đối với trường đại học thì tổng điểm >= 3.6
  • Còn ở trung tâm tiếng Anh thì tổng điểm >= 85%

Rõ ràng ở đây, chúng ta thấy cùng một quy tắc xếp loại Giỏi nhưng cách tính và kết quả đưa ra là khác nhau.

Thông qua 2 ví dụ này thì:

  • Làm thế nào để một lớp có thể sử dụng chung được các thuộc tính và phương thức của 2 hay nhiều lớp khác?
  • Làm thế nào để áp dụng các quy tắc khác nhau, tùy vào hoàn cảnh khác nhau của từng đối tượng?

=> Tất cả những điều này sẽ được giải quyết bằng cách sử dụng interface.

2. Interface là gì? Và cú pháp khai báo
2. Interface là gì? Và cú pháp khai báo
#1. Interface là gì?

Interface được hiểu là lớp nền (lớp base), tức là chỉ có nền móng thôi, tất cả mọi thứ còn lại là do chúng ta (các lập trình viên) tự xây dựng trên nền móng đó.

Interface như là một lớp mặt nạ, như là một bản thiết kế cho các class cùng cách thức hoạt động, nhưng có thể cùng hoặc khác nhau về bản chất bên trong.

#2. Cú pháp khai báo interface
[code language=”csharp”] <access_modifier> interface <tên_interface> <: tên_base_interface>
{

// interface member

}
[/code]

Trong đó:

  • <access_modifier> : là public hoặc internal, nếu không ghi rõ mặc định là internal.
  • interface : từ khóa khai báo một interface.
  • <tên_interface> : thường bắt đầu bằng chữ I, ví dụ: IShape, IAnimal, IStudent,…
  • <: tên_base_interface> : trường hợp có implement từ interface khác thì dấu 2 chấm : biểu thị sự implement, tiếp theo sau là tên base interface.

Ví dụ:

[code language=”csharp” highlight=”2,8″] // Khai báo interface IPeople
interface IPeople
{
// interface member
}

// Khai báo interface IStudent, implement từ interface IPeople
public interface IStudent : IPeople
{
// interface member
}
[/code]

3. Các đặc điểm của interface
3. Các đặc điểm của interface

Một interface trông có vẻ giống như một class, nhưng nó chỉ mô tả prototype của các thành phần methods, properties, indexersevents mà không định nghĩa chúng. Các thành phần không được sử dụng trong interface là: constructor, destructor, field, hằng, thành phần static.

Không thể khai báo hay chỉ định phạm vi truy cập (access modifiers) cho các thành phần bên trong interface. Các thành phần này sẽ mặc định là public.

Khai báo một interface IDung, bao gồm các thành phần ĐÚNG:

[code language=”csharp”] interface IDung
{
// method
void xyz();

// property
string name { get; set; }

// indexer
double this[int index] { get; set; }

// event
event EventHandler OnChanged;
}
[/code]

Khai báo một interface ISai, bao gồm các thành phần SAI:

[code language=”csharp”] interface ISai
{
// Không được sử dụng hàm [constructor] // error CS0526: Interfaces cannot contain constructors
ISai() { }

// Không được sử dụng hàm [destructor] // error CS0575: Only class types can contain destructors
~ISai() { }

// Không được chỉ định phạm vi truy cập (access modifiers)
// error CS0106: The modifier ‘public’ is not valid for this item
public void xyz();
// error CS0106: The modifier ‘protected’ is not valid for this item
protected void abc();

// Không được khai báo [field] // error CS0525: Interfaces cannot contain fields
int number;

// Không được khai báo hằng [const] // error CS0525: Interfaces cannot contain fields
public const double PI = 3.14;

// Không được định nghĩa hàm
// error CS0531: ‘ISai.xyz()’: interface members cannot have a definition
void xyz()
{
Console.WriteLine( "Print xyz" );
}

// Không được sử dụng thành phần [static] // error CS0106: The modifier ‘static’ is not valid for this item
static void xyz();
}
[/code]

Một interface sẽ được implement bởi các classesstructs, khi đó classes và structs bắt buộc phải định nghĩa tất cả các thành phần được mô tả trong interface.

Giả sử chúng ta có class Demo được implement từ interface IDung, thì bắt buộc class Demo phải định nghĩa tất cả các thành phần được khai báo trong interface IDung, kết quả như sau:

[code language=”csharp”] class Demo : IDung
{
// implement method
public void xyz()
{
throw new NotImplementedException();
}

// implement property
public string name
{
get
{
throw new NotImplementedException();
}

set
{
throw new NotImplementedException();
}
}

// implement indexer
public double this[int index] {
get
{
throw new NotImplementedException();
}

set
{
throw new NotImplementedException();
}
}

// implement event
public event EventHandler OnChanged;
}
[/code]

Mỗi class hoặc struct có thể implement một hoặc nhiều interface, trường hợp nhiều interface thì sẽ được ngăn cách nhau bằng dấu phẩy.

[code language=”csharp” highlight=”2,17,22″] // Ví dụ: class implement nhiều interface
class ConEch : IDongVatTrenCan, IDongVatDuoiNuoc
{
// implement method interface IDongVatTrenCan
public void Jump()
{
throw new NotImplementedException();
}

// implement method interface IDongVatDuoiNuoc
public void Swim()
{
throw new NotImplementedException();
}
}

interface IDongVatTrenCan
{
void Jump();
}

interface IDongVatDuoiNuoc
{
void Swim();
}
[/code]

Mỗi interface không được phép kế thừa từ một class nào cả. Chỉ được phép implement từ một hoặc nhiều interface, trường hợp nhiều interface thì sẽ được ngăn cách nhau bằng dấu phẩy. Và khi implement từ base interface thì không thực hiện (không định nghĩa) các thành phần của base interface.

Khác với class. Không thể tạo ra một đối tượng từ interface.

Nếu một lớp implement từ nhiều interface có cùng tên thành viên thì trong lớp phải chỉ rõ thành viên đó thuộc interface nào (explicit interface). Xem demo ở Ví dụ 3 của mục 4.

4. Demo code minh họa cách sử dụng
4. Demo code minh họa cách sử dụng

Ví dụ 1: Demo implement đơn interface. Chúng ta sẽ tạo ra một project MinhHoangBlog để quy định cách xếp loại cho học viên gồm các file sau:

  • File IRank.cs : interface IRank đặt ra khuôn mẫu về cách xếp loại cho học viên.
  • File Apolo.cs : class implement interface IRank để định nghĩa quy tắc xếp loại cho trung tâm tiếng Anh.
  • File University.cs : class implement interface IRank để định nghĩa quy tắc xếp loại cho trường đại học.
  • File Program.cs : chứa hàm main() thực hiện chương trình.

■ Nội dung file IRank.cs

[code language=”csharp” highlight=”6″] namespace MinhHoangBlog
{
interface IRank
{
// Khai báo prototype hàm xếp loại
string Ranking(float score);
}
}
[/code]

■ Nội dung file Apolo.cs

[code language=”csharp” highlight=”4,8″] namespace MinhHoangBlog
{
// Implement interface IRank
class Apolo : IRank
{
// Định nghĩa hàm Ranking
// theo quy tắc xếp loại của trung tâm
public string Ranking(float score)
{
if (score >= 85)
{
return "Distinction";
}
if (score >= 65)
{
return "Credit";
}
if (score >= 40)
{
return "Pass";
}
return "Fail";
}
}
}
[/code]

■ Nội dung file University.cs

[code language=”csharp” highlight=”4,8″] namespace MinhHoangBlog
{
// Implement interface IRank
class University : IRank
{
// Định nghĩa hàm Ranking
// theo quy tắc xếp loại của trường đại học
public string Ranking(float score)
{
if (score >= 3.6)
{
return "Xuat sac";
}
if (score >= 3.2)
{
return "Gioi";
}
if (score >= 2.5)
{
return "Kha";
}
if (score >= 2.0)
{
return "Trung Binh";
}
return "Khong xep loai";
}
}
}
[/code]

■ Nội dung file Program.cs

[code language=”csharp”] using System;

namespace MinhHoangBlog
{
class Program
{
static void Main(string[] args)
{
// Khai báo đối tượng của class
Apolo apolo = new Apolo();
University university = new University();

// Gọi hàm xếp loại tương ứng với từng đối tượng
Console.WriteLine("Apolo: " + apolo.Ranking(40));
Console.WriteLine("University: " + university.Ranking(2.6f));

Console.ReadKey();
}
}
}
[/code]

Kết quả chương trình

Kết quả chương trình


Ví dụ 2: Demo implement đa interface. Chúng ta sẽ tạo ra một project MinhHoangBlog để mô tả tính lưỡng cư của con ếch gồm các file sau:

  • File ILandAnimal : interface ILandAnimal đặt ra khuôn mẫu về cách di chuyển của động vật trên cạn.
  • File IWaterAnimal.cs : interface IWaterAnimal đặt ra khuôn mẫu về cách di chuyển của động vật dưới nước.
  • File Frog.cs : class implement 2 interface ILandAnimalIWaterAnimal để định nghĩa cách di chuyển ứng với khi trên mắt đất và lúc ở dưới nước.
  • File Program.cs : chứa hàm main() thực hiện chương trình.

■ Nội dung file ILandAnimal.cs

[code language=”csharp” highlight=”3″] namespace MinhHoangBlog
{
interface ILandAnimal
{
// Ếch: Di chuyển trên mặt đất là Nhảy
void Jump();
}
}
[/code]

■ Nội dung file IWaterAnimal.cs

[code language=”csharp” highlight=”3″] namespace MinhHoangBlog
{
interface IWaterAnimal
{
// Ếch: Di chuyển dưới nước là Bơi
void Swim();
}
}
[/code]

■ Nội dung file Frog.cs

[code language=”csharp” highlight=”6,9,15″] using System;

namespace MinhHoangBlog
{
// Implement 2 interface
class Frog : ILandAnimal, IWaterAnimal
{
// Định nghĩa method interface ILandAnimal
public void Jump()
{
Console.WriteLine( "Frog jumps" );
}

// Định nghĩa method interface IWaterAnimal
public void Swim()
{
Console.WriteLine( "Frog swims" );
}
}
}
[/code]

■ Nội dung file Program.cs

[code language=”csharp” highlight=”13,14″] using System;

namespace MinhHoangBlog
{
class Program
{
static void Main(string[] args)
{
// Khởi tạo đối tượng lớp con Ếch
Frog frog = new Frog();

// 2 cách di chuyển trên bờ và dưới nước
frog.Jump();
frog.Swim();

Console.ReadKey();
}
}
}
[/code]

Kết quả chương trình

Kết quả chương trình


Ví dụ 3: Demo implement đa interface và trong các interface có method trùng tên. Chúng ta sẽ tạo ra một project MinhHoangBlog để mô tả tính lưỡng cư của con ếch gồm các file sau:

  • File ILandAnimal : interface ILandAnimal khai báo prototype phương thức di chuyển Move().
  • File IWaterAnimal.cs : interface IWaterAnimal khai báo prototype phương thức di chuyển Move().
  • File Frog.cs : class implement 2 interface ILandAnimalIWaterAnimal để định nghĩa cách di chuyển ứng với khi trên mắt đất và lúc ở dưới nước.
  • File Program.cs : chứa hàm main() thực hiện chương trình.

■ Nội dung file ILandAnimal.cs

[code language=”csharp” highlight=”3″] namespace MinhHoangBlog
{
interface ILandAnimal
{
void Move();
}
}
[/code]

■ Nội dung file IWaterAnimal.cs

[code language=”csharp” highlight=”3″] namespace MinhHoangBlog
{
interface IWaterAnimal
{
void Move();
}
}
[/code]


■ Nội dung file Frog.cs

– Lúc này, vì 2 interface ILandAnimalIWaterAnimal có cùng tên phương thức là Move(), nên khi định nghĩa, chúng ta cần:

  1. Chỉ rõ phương thức Move() là của interface nào.
  2. Bỏ phạm vi truy cập là public đi.
public void Jump() → void ILandAnimal.Move()

public void Swim() → void IWaterAnimal.Move()
[code language=”csharp” highlight=”6,8,13″] using System;

namespace MinhHoangBlog
{
// Implement 2 interface
class Frog : ILandAnimal, IWaterAnimal
{
void ILandAnimal.Move()
{
Console.WriteLine( "Frog jumps" );
}

void IWaterAnimal.Move()
{
Console.WriteLine( "Frog swims" );
}
}
}
[/code]

■ Nội dung file Program.cs

– Vì 2 interface ILandAnimalIWaterAnimal có cùng tên phương thức là Move(), nên khi gọi, chúng ta cần: chỉ rõ phương thức Move() là của interface nào, bằng cách dùng từ khóa as để cast về interface tương ứng.

[code language=”csharp” highlight=”13,14″] using System;

namespace MinhHoangBlog
{
class Program
{
static void Main(string[] args)
{
// Khởi tạo đối tượng lớp con Ếch
Frog frog = new Frog();

// Dùng từ khóa「as」để cast về interface tương ứng khi gọi hàm
(frog as ILandAnimal).Move();
(frog as IWaterAnimal).Move();

Console.ReadKey();
}
}
}
[/code]

Kết quả chương trình

Kết quả chương trình

Cảm ơn bạn đã theo dõi. Đừng ngần ngại hãy cùng thảo luận với chúng tôi!

Giới thiệu

Minh Hoàng

Xin chào, tôi là Hoàng Ngọc Minh, hiện đang làm BrSE, tại công ty Toyota, Nhật Bản. Những gì tôi viết trên blog này là những trải nghiệm thực tế tôi đã đúc rút ra được trong cuộc sống, quá trình học tập và làm việc. Các bài viết được biên tập một cách chi tiết, linh hoạt để giúp bạn đọc có thể tiếp cận một cách dễ dàng nhất. Hi vọng nó sẽ có ích hoặc mang lại một góc nhìn khác cho bạn[...]

5 bình luận

Translate »