Vấn đề kế thừa các bất biến ở lớp con

Một phần của tài liệu Output file (Trang 59 - 63)

Đặc tả chuẩn OCL [29] không nói đến vấn đề thừa kế của các ràng buộc. Tuy nhiên, đối với một đối tượng lớp con có các hành vi giống với một đối tượng lớp cha, trong [14] đã chứng minh rằng một lớp con thừa kế các ràng buộc từ tất cả các lớp tổ tiên trực tiếp hay gián tiếp. Ví dụ, một lớp con phải duy trì các bất biến của lớp từ các lớp tổ tiên của nó. Tuy nhiên, trong nhiều trường hợp bất biến liên quan đến thuộc tính được thừa kế ở lớp con có thể có ràng buộc bị thay đổi so với lớp cha.

Trong AspectJ, các thuộc tính được thừa kế không được khai báo ở lớp con nên trình biên dịch không tìm thấy điểm đan kết (joint point) tương ứng nếu aspect kiểm chứng được cài đặt riêng cho lớp con này (thông qua bộ mô tả pointcut). Ví dụ aspect

được cài đặt để kiểm chứng thuộc tính withdrawalAmountPerDay của lớp SilverATM được thừa kế từ lớp cha ATMcard có mô tả pointcut dưới đây thì trình biên dịch sẽ không tìm được điểm đan kết tương ứng:

pointcut verify_withdrawalAmount(SilverATM card, int val): target(card) &&

set(int SilverATM.withdrawalAmountPerDay) && args(val);

Bộ mô tả pointcut định nghĩa field set joint point cho thuộc tính của lớp cha khai báo thuộc tính này thì các đối tượng của các lớp con có thừa kế thuộc tính này cũng có

Đan kết Cài đặt Cài đặt Mô hình UML Các ràng buộc OCL Mã nguồn Java Các Aspect kiểm chứng Chương trình Java chứa mã tự kiểm chứng

chung field set joint point này nên khi giá trị của thuộc tính ứng với đối tượng của bất kỳ lớp nào (lớp con hay lớp cha) thay đổi thì joint point này sẽ được so khớp. Do đó đối với trường hợp bất biến của lớp con có ràng buộc không thay đổi so với lớp cha thì aspect được cài đặt để kiểm chứng bất biến của lớp cha sẽ có hiệu lực ở lớp con do lớp. Cụ thể là aspect được cài đặt để kiểm chứng bất biến liên quan đến thuộc tính của đối tượng của lớp cha sẽ được dùng để kiểm chứng bất biến liên quan đến thuộc tính được thừa kế của các đối tượng của các lớp con. Do đó chúng ta chỉ cần cài đặt các

aspect để kiểm chứng các bất biến cho lớp cha có khai báo thuộc tính cần kiểm chứng. Tức là nếu giá trị của thuộc tính liên quan đến bất biến cần được kiểm chứng thay đổi tại thể hiện của bất kỳ lớp nào có thuộc tính đó thì joint point tương ứng sẽ được so khớp và advice tương ứng sẽ được thực hiện. Như vậy, các mã kiểm chứng không cần viết lại cho các lớp con.

Trong ví dụ được mô tả trong mục 3.4, chúng ta giả sử lớp ATMcard và các lớp con SilverATM và GoldATM đều có các bất biến với các ràng buộc withdrawalAmountPerDay <=2000 và balanceAmount>=0. Do thuộc tính withdrawalAmountPerDay và balanceAmount không được khai báo lại tại hai lớp con SilverATM và GoldATM nên không thể cài đặt mã kiểm chứng riêng cho hai lớp con này mà phải được cài đặt tại lớp cha có khai báo thuộc tính cần kiểm chứng. Khi giá trị của thuộc tính withdrawalAmountPerDay hay balanceAmount được thay đổi tại đối tượng của lớp cha hay các lớp con thì joint point sẽ được so khớp và advice tương ứng sẽ được thực hiện. Để kiểm chứng bất biến cho cả ba lớp ATMcard, SilverATM và GoldATM, ta xây dựng một aspect có tên là ATMcardVerifier như sau:

public aspect ATMcardVerifier {

pointcut verify_withdrawalAmount(ATMcard card, int val): target(card) &&

set(int ATMcard.withdrawalAmountPerDay) && args(val);

void around(ATMcard card, int val): verify_withdrawalAmount(card, val) { if(val>2000) {

System.out.println(thisJoinPoint.getTarget().getClass().g etName()+".withdrawalAmountPerDay<=2000");

} else {

proceed(card, val); // Cho phép thực hiện tiếp }

pointcut verify_balance(ATMcard card, int val): target(card) && set(int ATMcard.balanceAmount) && args(val);

void around(ATMcard card, int val): verify_balance(card, val){ if(val<0) {

System.out.println(thisJoinPoint.getTarget().getClass().g etName()+".balanceAmount>=0");

} else proceed(card, val); }

}

Pointcut verify_withdrawalAmount được khai báo cho field set joint point là set(int ATMcard.withdrawalAmountPerDay) nhằm chèn đoạn mã kiểm chứng vào bất kỳ nơi nào làm thay đổi giá trị thuộc tính withdrawalAmountPerDay của ATMcard và các lớp con của nó là SilverATM và GoldATM. Điều đó có nghĩa là bất cứ khi nào giá trị của thuộc tính withdrawalAmountPerDay bị gán giá trị thì joint point ứng với bộ mô tả pointcut verify_withdrawalAmount trong đoạn mã kiểm chứng được so khớp. Chúng ta có thể làm được như vậy là vì mặc dù aspect ATMcardVerifier được cài đặt cho lớp ATMcard nhưng cũng có hiệu ứng đối với các lớp con SilverATM và GoldATM. Tương tự đối với pointcut verify_balance.

Advice trong aspect kiểm chứng được dùng là around advice nhằm ngăn sự thay đổi giá trị thuộc tính khi có sự vi phạm ràng buộc xảy ra. Điều đó có nghĩa là khi có sự vi phạm ràng buộc xảy ra thì lỗi vi phạm được thông báo hoặc lưu vết lại, đồng thời không cho phép thực hiện tiếp đoạn mã tại joint point được so khớp (hàm proceed() không được gọi) do đó giá trị của thuộc tính không bị thay đổi. Khi ràng buộc không bị vi phạm thì cho phép đoạn mã tiếp theo tại joint point được so khớp thực hiện bằng việc gọi hàm proceed().

Trong trường hợp chỉ cần thông báo hoặc lưu vết các vi phạm bất biến mà không ngăn chặn sự thay đổi giá trị của thuộc tính thì chúng ta có thể dùng before advice như sau:

public aspect ATMcardVerifier {

pointcut verify_withdrawalAmount(ATMcard card, int val): target(card) &&

set(int ATMcard.withdrawalAmountPerDay) && args(val);

before(ATMcard card, int val): verify_withdrawalAmount(card, val) {

System.out.println(thisJoinPoint.getTarget().getClass().g etName()+".withdrawalAmountPerDay<=2000");

} }

pointcut verify_balance(ATMcard card, int val): target(card) && set(int ATMcard.balanceAmount) && args(val);

before(ATMcard card, int val): verify_balance(card, val){ if(val<0) { System.out.println(thisJoinPoint.getTarget().getClass().g etName()+".balanceAmount>=0"); } } }

hoặc after advice như sau:

public aspect ATMcardVerifier {

pointcut verify_withdrawalAmount(ATMcard card, int val): target(card) &&

set(int ATMcard.withdrawalAmountPerDay) && args(val);

after(ATMcard card, int val):

verify_withdrawalAmount(card, val) { if(val>2000) { System.out.println(thisJoinPoint.getTarget().getClass().g etName()+".withdrawalAmountPerDay<=2000"); } }

pointcut verify_balance(ATMcard card, int val): target(card) && set(int ATMcard.balanceAmount) && args(val);

after(ATMcard card, int val): verify_balance(card, val){ if(val<0) {

System.out.println(thisJoinPoint.getTarget().getClass().g etName()+".balanceAmount>=0");

} } }

Với before advice, các thông tin của các bất biến bị vi phạm sẽ được lưu lại trước khi giá trị của thuộc tính có ràng buộc bị vi phạm được thay đổi. Ngược lại, đối với

after advice thì các thông tin của các bất biến bị vi phạm sẽ được lưu lại sau khi giá trị của thuộc tính có ràng buộc bị vi phạm được thay đổi.

Một phần của tài liệu Output file (Trang 59 - 63)

Tải bản đầy đủ (PDF)

(92 trang)