Ngôn Ngữ Lập Trình C#
// bộ khởi tạo lớp Document lấy một tham số
public Document( string s)
{
Console.WriteLine(“Creating document with: {0}”, s);
}
// thực thi giao diện IStorable
public void Read()
{
Console.WriteLine(“Implementing the Read Method for IStorable”);
}
public void Write( object o)
{
Console.WriteLine(“Implementing the Write Method for IStorable”);
}
public int Status
{
get
{
return status;
}
set
{
status = value;
}
}
// thực thi ICompressible
public void Compress()
{
Console.WriteLine(“Implementing Compress”);
}
}
public class Tester
{
public static void Main()
{
// tạo đối tượng document
Document doc = new Document(“Test Document”);
// gán đối tượng cho giao diện
IStorable isDoc = doc as IStorable;
if ( isDoc != null)
{
isDoc.Read();
}
else
{
Console.WriteLine(“IStorable not supported”);
}
ICompressible icDoc = doc as ICompressible;
if ( icDoc != null )
{
icDoc.Compress();
Thực Thi Giao Diện
184
.
.
Ngôn Ngữ Lập Trình C#
}
else
{
Console.WriteLine(“Compressible not supported”);
{
Console.WriteLine(“Encryptable not supported”);
}
}
Thực Thi Giao Diện
185
.
.
Ngôn Ngữ Lập Trình C#
}
Kết quả:
Creating document with: Test Document
Implementing the Read Method for IStorable
Implementing Compress
Implementing LogSavedBytes
Implementing Compress
Implementing LogOriginalSize
Implementing LogSaveBytes
Implementing Compress
Implementing the Read Method for IStorable
Implementing Encrypt
Ví dụ 8.2 bắt đầu bằng việc thực thi giao diện IStorable và giao diện ICompressible. Sau đó
là phần mở rộng đến giao diện ILoggedCompressible rồi sau đó kết hợp cả hai vào giao diện
IStorableCompressible. Và giao diện cuối cùng trong ví dụ là IEncrypt.
Chương trình Tester tạo đối tượng Document mới và sau đó gán lần lượt vào các giao diện
khác nhau. Khi một đối tượng được gán cho giao diện ILoggedCompressible, chúng ta có thể
dùng giao diện này để gọi các phương thức của giao diện ICompressible bởi vì ILogged-
Compressible mở rộng và thừa kế các phương thức từ giao diện cơ sở:
doc.status = -1;
doc.Read();
hay là ta có thể tạo thể hiện của giao diện bằng cách gán đối tượng Document cho một kiểu
dữ liệu giao diện, và sau đó sử dụng giao diện này để truy cập các phương thức:
IStorable isDoc = (IStorable) doc;
isDoc.status = 0;
isDoc.Read();
Ghi chú: Cũng như đã nói trước đây, chúng ta không thể tạo thể hiện của giao diện một
cách trực tiếp.Do đó chúng ta không thể thực hiện như sau:
IStorable isDoc = new IStorable();
Tuy nhiên chúng ta có thể tạo thể hiện của lớp thực thi như sau:
Document doc = new Document(“Test Document”);
Sau đó chúng ta có thể tạo thể hiện của giao diện bằng cách gán đối tượng thực thi đến kiểu
dữ liệu giao diện, trong trường hợp này là IStorable:
IStorable isDoc = (IStorable) doc;
Chúng ta có thể kết hợp những bước trên như sau:
IStorable isDoc = (IStorable) new Document(“Test Document”);
Nói chung, cách thiết kế tốt nhất là quyết định truy cập những phương thức của giao diện
thông qua tham chiếu của giao diện. Do vậy cách tốt nhất là sử dụng isDoc.Read(), hơn là sử
dụng doc.Read() trong ví dụ trước. Truy cập thông qua giao diện cho phép chúng ta đối xử
giao diện một cách đa hình. Nói cách khác, chúng ta tạo hai hay nhiều hơn những lớp thực thi
giao diện, và sau đó bằng cách truy cập lớp này chỉ thông qua giao diện.
Gán đối tượng cho một giao diện
Trong nhiều trường hợp, chúng ta không biết trước một đối tượng có hỗ trợ một giao
diện đưa ra. Ví dụ, giả sử chúng ta có một tập hợp những đối tượng Document, một vài đối
tượng đã được lưu trữ và số còn lại thì chưa. Và giả sử chúng ta đã thêm giao diện giao diện
thứ hai, ICompressible cho những đối tượng để nén dữ liệu và truyền qua mail nhanh chóng:
interface ICompressible
{
Thực Thi Giao Diện
ICompressible.
Ví dụ 8.3: Sử dụng toán tử is.
using System;
interface IStorable
{
void Read();
void Write(object obj);
int Status { get; set; }
}
// giao diện mới
Thực Thi Giao Diện
188
.
.
Ngôn Ngữ Lập Trình C#
interface ICompressible
{
void Compress();
void Decompress();
}
// Document thực thi IStorable
public class Document : IStorable
{
public Document( string s)
{
Console.WriteLine(“Creating document with: {0}”, s);
}
// IStorable
public void Read()
static void Main()
{
Document doc = new Document(“Test Document”);
// chỉ gán khi an toàn
if ( doc is IStorable )
{
IStorable isDoc = (IStorable) doc;
isDoc.Read();
}
// việc kiểm tra này sẽ sai
if ( doc is ICompressible )
{
ICompressible icDoc = (ICompressible) doc;
icDoc.Compress();
}
}
}
Trong ví dụ 8.3, hàm Main() lúc này sẽ thực hiện việc gán với interface khi được kiểm tra
hợp lệ. Việc kiểm tra này được thực hiện bởi câu lệnh if:
if ( doc is IStorable )
Biểu thức điều kiện sẽ trả về giá trị true và phép gán sẽ được thực hiện khi đối tượng có thực
thi giao diện bên phải của toán tử is.
Tuy nhiên, việc sử dụng toán tử is đưa ra một việc không có hiệu quả. Để hiểu được điều này,
chúng ta xem đoạn chương trình được biên dịch ra mã IL. Ở đây sẽ có một ngoại lệ nhỏ, các
dòng bên dưới là sử dụng hệ thập lục phân:
IL_0023: isinst ICompressible
IL_0028: brfalse.s IL_0039
IL_002a: ldloc.0
IL_002b: castclass ICompressible
Document doc = new Document(“Test Document”);
IStorable isDoc = doc as IStorable;
if ( isDoc != null )
{
isDoc.Read();
}
else
{
Console.WriteLine(“IStorable not supported”);
}
ICompressible icDoc = doc as ICompressible;
if ( icDoc != null)
{
icDoc.Compress();
}
else
{
Console.WriteLine(“Compressible not supported”);
}
Thực Thi Giao Diện
191
.
.
Ngôn Ngữ Lập Trình C#
}
Ta có thể so sánh đoạn mã IL sau với đoạn mã IL sử dụng toán tử is trước sẽ thấy đoạn mã
sau có nhiều hiệu quả hơn:
IL_0023: isinst ICompressible
IL_0028: stloc.2
IL_0029: ldloc.2
Thực Thi Giao Diện
192
.
.