Tải bản đầy đủ (.pdf) (13 trang)

Tài liệu Cơ chế ủy quyền và sự kiện phần 3 docx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (197.49 KB, 13 trang )

Console.WriteLine(“Sharpening image”);

}


public static void Rotate()

{


Console.WriteLine(“Rotating image”);

}


// gọi các ủy quyền để thực hiện hiệu ứng
public void ProcessImage()
{


for (int i = 0; i < numEffectsRegistered; i++)

{


arrayOfEffects[i]();

}

}



// biến thành viên

private DoEffect[] arrayOfEffects;

private Image image;

private int numEffectsRegistered = 0;

}


// lớp Test để kiểm chứng chương trình public class Test
{


public static void Main()

{

Image theImage = new Image();

// do không có GUI để thực hiện chúng ta sẽ chọn lần

// lượt các hành động và thực hiện

ImageProcessor theProc = new ImageProcessor(theImage);
theProc.AddToEffects(theProc.BlurEffect);
theProc.AddToEffects(theProc.FilterEffect);
theProc.AddToEffects(theProc.RotateEffect);

theProc.AddToEffects(theProc.SharpenEffect);
theProc.ProcessImage();
}

}

}



Kết quả:

An image created
Blurring image
Filtering image
Rotate image
Sharpening image


Trong ví dụ trên, đối tượng ImageProcessor được tạo ra và những hiệu ứng được
thêm vào. Nếu người dùng chọn làm mờ trước khi lọc ảnh, thì đơn giản là được đưa
vào mảng ủy quyền theo thứ tự tương ứng. Tương tự như vậy, bất cứ hành động lựa
chọn nào của người dùng mong muốn, ta đưa thêm nhiều ủy quyền vào trong tập hợp.
Chúng ta có thể tưởng tượ
ng việc hiển thị thứ tự hành động này trong một danh sách
listbox
và cho phép người sử dụng sắp xếp lại phương thức, di chuyển chúng lên xuống
trong danh sách. Khi các hành động này được sắp xếp lại thì chúng ta chỉ cần thay
đổi thứ tự trong tập hợp. Ngoài ra ta cũng có thể đưa các hoạt động này vào trong
cơ sở dữ liệu rồi sau đó đọc chúng lúc thực hiện.

Ủ y quyền dễ dàng cung cấp động cho ta các ph
ương thức được gọi theo một thứ tự xác
định

Multicasting
Cơ chế multicasting cho phép gọi hai phương thức thực thi thông qua một ủy
quyền đơn. Điều này trở nên quan trọng khi xử lý các sự kiện, sẽ được thảo luận
trong phần cuối của chương.

Mục đích chính là có một ủy quyền có thể gọi thực hiện nhiều hơn một phương
thức. Điều này hoàn toàn khác với việc có một tập hợp các ủy quyền, vì mỗi trong số
chúng chỉ gọi được duy nhất một phương thức. Trong ví dụ trước, tập hợp được sử
dụng để lưu giữ các ủy quyền khác nhau. Tập hợp này cũng có thể thêm m
ột ủy
quyền nhiều hơn một lần, và sử dụng tập hợp để sắp xếp lại các ủy quyền và điều
khiển thứ tự hành động được gọi.
Với Multicasting chúng ta có thể tạo một ủy quyền đơn và cho phép gọi nhiều
phương thức được đóng. Ví dụ, khi một nút lệnh được nhấn chúng ta có thể muốn
thực hiện nhiều h
ơn một hàh động. Để làm được điều này chúng ta có thể đưa cho
button một tập hợp các ủy quyền, nhưng để sáng rõ hơn và dễ dàng hơn là tạo một ủy
quyền Multicast.
Bất cứ ủy quyền nào trả về giá trị void là ủy quyền multicast, mặc dù vậy ta có thể đối
xử với
nó như là ủy quyền bình thường cũng không sao. Hai ủy quyền Multicast có thể được kết
hợp
với nhau bằng phép toán cộng (+). Kết quả là một ủy quyền Multicast mới và gọi
đến tất cả các phương thức thực thi nguyên thủy của cả hai bên. Ví dụ, giả sử
Writer và Logger là ủy quyền trả về giá trị void, dòng lệnh theo sau sẽ kết hợp
chúng lại với nhau và tạo ra một ủy quyền Multicast mới:

myMulticastDelegate = Writer + Logger;
Chúng ta cũng có thể thêm những ủy quyền vào trong ủy quyền Multicast bằng toán
t
ử cộng bằng (+=). Phép toán này sẽ thêm ủy quyền ở phía bên phải của toán tử
vào ủy quyền Multicast ở bên trái. Ví dụ minh họa như sau, giả sử có Transmitter và
myMulticastDelegate
là những ủy quyền, lệnh tiếp theo sau đây sẽ thực hiện việc thêm ủy quyền Transmitter
vào trong myMulticastDelegate:
myMulticastDelegate += Transmitter;
Để hiểu rõ ủy quyền Multicast được tạo ra và sử dụng, chúng ta sẽ từng bước tìm
hiểu thông qua ví dụ 11.3 bên dưới, trong ví dụ minh họa này chúng ta sẽ tạ
o ra
một lớp có tên gọi là MyClassWithDelegate lớp này định nghĩa một delegate,
delegate này lấy một tham số là chuỗi và không có giá trị trả về:
void delegate void StringDelegate( string s);
Sau đó chúng ta định một lớp gọi là MyImplementingClass lớp này có ba phương thức,
tất cả các phương thức này đều trả về giá trị void và nhận một chuỗi làm tham số:
WriteString, LogString, và Transmitting. Phương thức đầu tiên viết một chuỗi xuất
ra màn hình tiêu chuẩn, chuỗi thứ hai mô phỏng viết vào mộ
t log file, và phương
thức thứ ba mô phỏng việc chuyển một chuỗi qua Internet. Chúng ta tạo thể hiện
delegate để gọi những phương thức tương ứng:

Writer(“String passed to Writer\n”);
Logger(“String passed to Logger\n”);
Transmitter(“String passed to Transmitter\n”);
Để xem cách kết hợp các delegate, chúng ta tạo một thể hiện delegate khác:

MyClassWithDelegate.StringDelegate myMulticastDelegate;


và gán cho delegate này kết quả của phép cộng hai delegate cho trước:

myMulticastDelegate = Writer + Logger;
Tiếp theo chúng ta thêm vào delegate này một delegate nữa bằng cách sử dụng toán tử
(+=):

myMulticastDelegate += Transmitter;
Cuối cùng, chúng ta thực hiện việc xóa deleagate bằng sử dụng toán tử (-=):

DelegateCollector -= Logger;
Sau đây là toàn bộ ví dụ minh họa.
Ví dụ 11.3: Kết hợp các delegate.


namespace Programming_CSharp

{


using System;

public class MyClassWithDelegate

{


// khai báo delegate

public delegate void StringDelegate(string s);


}


public class MyImplementingClass

{


public static void WriteString( string s)

{


Console.WriteLine(“Writing string {0}”, s);

}


public static void LogString( string s)

{


Console.WriteLine(“Logging string {0}”, s);

}


public static void TransmitString( string s)


{


Console.WriteLine(“Transmitting string {0}”, s);

}

}


public class Test

{


public static void Main()

{


// định nghĩa 3 StringDelegate

MyClassWithDelegate.StringDelegate Writer, Logger, Transmitter;

// định nghĩa một StringDelegate khác thực hiện Multicasting

MyClassWithDelegate.StringDelegate myMulticastDelegate;

// tạo thể hiện của 3 delegate đầu tiên và truyền vào phương thức thực thi


Writer = new
MyClassWithDelegate.StringDelegate(
MyImplementingClass.WriteString);
Logger = new
MyClassWithDelegate.StringDelegate(
MyImplementingClass.LogString);
Transmitter = new
MyClassWithDelegate.StringDelegate(
MyImplementingClass.TransmitString);
// gọi phương thức delegate Writer

Writer(“String passed to Writer\n”);

// gọi phương thức delegate Logger

Logger(“String passed to Logger\n”);

//gọi phương thức delegate Transmitter

Transmitter(“String passed to Transmitter\n”);

// thông báo người dùng rằng đã kết hợp hai delegate vào

// trong một multicast delegate

Console.WriteLine(“myMulticastDelegate = Writer + Logger”);

// k
ết hợp hai delegate
myMulticastDelegate = Writer +

Logger;
// gọi phương thức delegate, hai phương thức sẽ được thực hiện
myMulticastDelegate(“First string passed to Collector”);
// bảo với người sử dụng rằng đã thêm delegate thứ 3 vào

// trong Multicast delegate

Console.WriteLine(“\nmyMulticastDeleagte += Transmitter”);

// thêm delegate thứ ba vào
myMulticastDelegate += Transmitter;
// gọi thực thi Multicast delegate, cùng một lúc ba

// phương thức sẽ cùng được gọi thực hiện
myMulticastDelegate(“Second string passed to
Collector”);
// bảo với người sử dụng rằng xóa delegate Logger

Console.WriteLine(“\nmyMulticastDelegate -= Logger”);

// xóa delegate Logger
myMulticastDelegate -=
Logger;
// gọi lại delegate, lúc này chỉ còn thực hiện hai phương thức
myMulticastDelegate(“Third string passed to Collector”);
}// end Main

}// end class
}// end namespace



Kết quả:

Writing string String passed to Writer
Logging string String passed to Logge
r

Transmitting string String passed to Transmitter

myMulticastDelegate = Writer + Logger

Writing string First string passed to Collector
Logging string First string passed to Collector
myMulticastDelegate += Transmitter
Writing string Second string passed to Collector Logging
string Second string passed to Collector Transmitting string
Second string passed to Collector myMulticastDelegate -=
Logger
Writing string Third string passed to Collector

Transmitting string Third string passed to Collector

Trong ví dụ trên, những thể hiện delegate được định nghĩa và ba delegate đầu tiên
Writer, Logger, và Transmitter được gọi ra. Delegate thứ tư myMulticastDelegate
được gán bằng cách kết hợp hai delegate đầu, và khi nó được gọi, thì dẫn đến là cả
hai delegate cũng được gọi. Khi delegate thứ ba được thêm vào, và kết quả là khi
myMulticastDelegate được gọi thì tất cả ba phương thức delegate cũng được thực
hiệ
n. Cuối cùng, khi Logger được xóa khỏi delegate, và khi myMulticastDelegate
được gọi thì chỉ có hai phương thức thực thi.

Multicast delegate được thể hiện tốt nhất trong việc ứng dụng xử lý các sự kiện. Khi
một sự kiện ví dụ như một nút lệnh được nhấn, thì một multicast delegate tương ứng
sẽ gọi đến một loạt các phương thức xử lý sự kiện để đáp ứng lại với các sự kiệ
n này.
Sự kiện

Trong môi trường giao diện đồ họa (Graphical User Interfaces: GUIs), Windows
hay trong trình duyệt web đòi hỏi các chương trình phải đáp ứng các sự kiện. Một sự
kiện có thể
là một nút lệnh được nhấn, một mục trong menu được chọn, hành động sao chép tập
tin hoàn thành, Hay nói ngắn gọn là một hành động nào đó xảy ra, và ta phải đáp
ứng lại sự kiện đó. Chúng ta không thể đoán trước được khi nào thì các sự
kiện sẽ
xuất hiện. Hệ thống sẽ chờ cho đến khi nhận được sự kiện, và sẽ chuyển vào cho trình
xử lý sự kiện thực hiện.
Trong môi trường giao diện đồ họa, bất cứ thành phần nào cũng có thể đưa ra sự kiện.
Ví dụ,
khi chúng ta kích vào một nút lệnh, nó có thể đưa ra sự kiện Click. Khi chúng ta thêm
một mục vào danh sách, nó sẽ đưa ra sự kiện ListChanged.
Cơ chế publishing và subscribing

Trong ngôn ngữ C#, bất cứ đối tượng nào cũng có thể publish một tập hợp các sự
kiện để cho các lớp khác có thể đăng ký. Khi một lớp publish đưa ra một sự kiện, thì
tất cả các lớp đã đăng ký sẽ được nhận sự cảnh báo.
Ghi chú: Tác giả Gamma (Addison Wesley, 1995) mô tả cơ chế này như sau: “Định
nghĩa một đến nhiều sự
phụ thuộc giữa những đối tượng do đó khi một đối tượng
thay đổi trạng thái, tất cả các đối tượng khác phụ thuộc vào nó sẽ được cảnh báo và
cập nhật một cách tự động”.
Với cơ chế này, đối tượng của chúng ta có thể nói rằng “Ở đây có những thứ mà tôi có

thể thông báo cho bạn” và những lớp khác có thể đăng ký đáp rằng “Vâng, hãy báo cho
tôi bi
ết
khi chuyện đó xảy ra”. Ví dụ, một nút lệnh có thể cảnh báo cho bất cứ thành phần nào khi
nó được nhấn. Nút lệnh này được gọi là publisher bởi vì nó phân phát sự kiện Click và
những
lớp khác là các lớp subscriber vì chúng đăng ký nhận sự kiện Click này.

Sự kiện và delegate

Những sự kiện trong C# được thực thi với những delegate. Lớp publisher định nghĩa
một delegate và những lớp subscriber phải thực thi. Khi một s
ự kiện xuất hiện thì
phương thức
của lớp subscriber được gọi thông qua delegate.
Một phương thức được dùng để xử lý các sự kiện thì được là trình xử lý sự kiện
(event handler). Chúng ta có thể khai báo trình xử lý sự kiện này như chúng ta đã
làm với bất cứ delegate khác.
Theo quy ước, những trình xử lý sự kiện trong .NET Framework trả về giá trị void và
lấy hai tham số. Tham số đầu tiên là nguồn dẫn đến sự ki
ện, đây chính là đối tượng
publisher. Và tham số thứ hai là đối tượng dẫn xuất từ lớp EventArgs. Yêu cầu chúng
ta phải thực hiện trình xử lý sự kiện theo mẫu như trên.
EventArgs là lớp cơ sở cho tất cả các dữ liệu về sự kiện, lớp EventArgs thừa kế tất
cả các phương thức của nó từ Object, và thêm vào một trường public static empty thể
hiện một sự kiện không có trạng thái (cho phép s
ử dụng hiệu quả những sự kiện
không trạng thái). Lớp dẫn xuất từ EventArgs chứa những thông tin về sự kiện.
Sự kiện là thuộc tính của lớp phát ra sự kiện. Từ khóa event điều khiển cách thuộc
tính sự kiện được truy cập bởi các lớp subscriber. Từ khóa event được thiết kế để duy

trì cho cách thể hiện publish/ subscribe.
Giả sử chúng ta muốn tạo một lớp Clock dùng những sự kiện để cảnh báo
những lớp subscriber bất cứ khi nào đồng hồ hệ thống thay đổi giá trị trong một giây.
G
ọi sự kiện này là OnSecondChange. Chúng ta khai báo sự kiện và kiểu delegate xử lý
sự kiện của nó như sau:
[attributes] [modifiers] event type
member- name
Ví dụ khai báo như sau:


public event SecondChangeHandler OnSecondChange;
Trong ví dụ này ta không dùng thuộc tính, modifier ở đây là abstract, new,
override, static, virtual, hay là một trong bốn access modifier, trong trường hợp này
public. Modifier được theo sau bởi từ khóa event.
Trường type trong trường hợp ví dụ này là delegate mà chúng ta muốn liên hệ với sự
kiện, ở đây là SecondChangeHandler.
Tên thành viên là tên của sự kiện, trong tr
ường hợp này là OnSecondChange. Thông
thường, tên sự kiện bắt đầu với từ On.
Tóm lại, trong sự khai báo này OnSecondChange là sự kiện được thực thi bởi delegate
có kiểu là SecondChangeHandler.
Ta có khai báo cho delegate này như sau:

public delegate void SecondChangeHandler( object
clock, TimeInfoEventArgs timeInformation);
Như đã nói trước đây, theo quy ước một trình xử lý sự kiện phải trả về giá trị void và phải
lấy
hai tham số: nguồn phát ra sự kiện (trong trường hợp này là clock) và một đối tượng dẫn
xuất

từ
EventArgs, là TimeInfoEventArgs. Lớp TimeInfoEventArgs được định nghĩa như sau:

public class TimeInfoEventArgs : EventArgs

{


public TimeInfoEventArgs(int hour, int minute, int second)

{


this.hour = hour;
this.minute = minute;
this.second = second;
}


public readonly int hour;
public readonly int minute;
public readonly int second;
}


Đối tượng TimeInfoEventArgs sẽ có thông tin về giờ phút giây hiện thời. Nó định nghĩa
một
bộ khởi tạo, ba phương thức, một biến nguyên readonly.
Ngoài việc thêm vào một sự kiện và delegate, lớp đối tượng Clock có ba biến thành viên
là :

hour, minute, và second. Cuối cùng là một phương thức Run():


×