Trong nhiều trường hợp, bất biến liên quan đến thuộc tính được kế thừa ở lớp con có ràng buộc thay đổi so với lớp cha. Như đã trình bày ở phần trên, để kiểm chứng bất biến liên quan đến thuộc tính được thừa kế này aspect kiểm chứng phải được cài đặt cho lớp cha có khai báo thuộc tính này. Tuy nhiên, để cài đặt được mã kiểm tra tương ứng với các ràng buộc khác nhau giữa lớp cha và các lớp con cần phân biệt được joint point được so khớp tại đối tượng của lớp nào. Kỹ thuật kiểm tra này sẽ được trình bày bên dưới.
Đối với ví dụ trong mục 3.4, do hai lớp SilverATM và GoldATM có các thuộc tính withdrawalAmountPerDay và balanceAmount được kế thừa từ lớp tổ tiên là ATMcard nên ta không thể cài đặt mã kiểm tra riêng cho các lớp con này. Để kiểm chứng các bất biến của các lớp con có ràng buộc thay đổi so với lớp cha sử dụng phương pháp AOP được cài đặt bằng đặc tả ngôn ngữ AspectJ, chúng ta tiến hành cài đặt các aspect để kiểm chứng các bất biến liên quan đến các thuộc tính withdrawalAmountPerDay và balanceAmount của lớp cha ATMcard khai báo các thuộc tính đó. Do các lớp SilverATM và GoldATM có các thuộc tính withdrawalAmountPerDay và balanceAmount được kế thừa từ lớp cha ATMcard nên
aspect được cài đặt để kiểm chứng bất biến liên quan đến các thuộc tính này của các lớp con SilverATM và GoldATM có cùng các field set joint point tương ứng với cha ATMcard. Trong advice thực hiện kiểm chứng sẽ có đoạn mã kiểm tra joint point được so khớp tại đối tượng đích là thể hiện của lớp ATMcard, SilverATM hay GoldATM để có đoạn mã kiểm tra theo các ràng buộc ứng với lớp tương ứng. Aspect đó 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) {
Object sl = thisJoinPoint.getTarget(); String objName=sl.getClass().getName(); if(objName.equals("ATMcard") && val>2000) {
System.out.println("ATMcard.withdrawalAmountPerDay <=2000");
} else if(objName.equals("SilverATM") && val>3000) {
System.out.println("SilverATM.withdrawalAmountPerDay<=300 0");
} else if(objName.equals("GoldATM") && val>5000) {
System.out.println("GoldATM.withdrawalAmountPerDay <= 5000");
} 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){ Object sl = thisJoinPoint.getTarget();
String objName=sl.getClass().getName();
if(objName.equals("ATMcard") && val<0) {
System.out.println("ATMcard.balanceAmount>=0"); } else if(objName.equals("SilverATM") && val<-5000) {
System.out.println("SilverATM.balanceAmount>=-5000"); } else if(objName.equals("GoldATM") && val<-10000){
System.out.println("GoldATM.balanceAmount>=-10000"); } else {
proceed(card, val); // Cho phép thực hiện tiếp
} } }
Theo đoạn mã trên ta chỉ cần xây dựng một aspect ATMcardVerifier, sau đó sử dụng phương thức getTarget() của đối tượng thisJointPoint lấy đối tượng đích mà joint point được so khớp và phương thức getClass() của đối tượng đích để lấy tên lớp của đó. Sau khi lấy được tên lớp, ta tiến hành so sánh tên lớp thu được với các tên lớp gốc ATMcard, SilverATM và GoldATM để cài đặt các mã kiểm tra phù hợp.
Như vậy, phương pháp trên dựa vào việc hiệu ứng của aspect một cách không tường minh trong AspectJ. Ta có thể thực hiện kiểm chứng các bất biến của các đối tượng theo phương pháp thừa kế các aspect một cách tường minh. Theo luật thừa kế đã được trình bày tại mục 1.4.6, một aspect chỉ kế thừa được từ một aspect được khai báo là một aspect trừu tượng. Pointcut và advice được khai báo ở aspect cha sẽ được
aspect con kế thừa. Theo tính ưu tiên của advice được đề cập trong mục 2.4.4 thì đối với các advice cùng chia sẻ một joint point thì advice của aspect con có thứ tự ưu tiên cao hơn advice của aspect cha.
Đối với ví dụ trong mục 3.4, chúng ta cài đặt một aspect trừu tượng có tên là ATMcardVerifier chứa các mô tả pointcut cho field set joint point set(int ATMcard.withdrawalAmount) và set(int ATMcard.balanceAmount) để kiểm chứng bất biến liên quan đến các thuộc tính withdrawalAmountPerDay và balanceAmount của đối tượng của lớp ATMcard. Aspect này cũng chứa hai around advice cài đặt các đoạn mã kiểm chứng tương ứng. Do advice của các lớp con sẽ trả quyền thực hiện
advice về lớp cha khi advice của chúng được thực hiện xong và không có ngoại lệ nên
advice của lớp cha này phải tiến hành kiểm tra xem joint point có được so khớp tại đối tượng của lớp ATMcard hay không để cài đặt mã kiểm tra phù hợp.
public abstract 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) {
Object sl = thisJoinPoint.getTarget(); String objName=sl.getClass().getName(); if(objName.equals("ATMcard") && val>2000) {
System.out.println("ATMcard.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){ Object sl = thisJoinPoint.getTarget();
String objName=sl.getClass().getName(); if(objName.equals("ATMcard") && val<0) {
System.out.println("ATMcard.balanceAmount>=0"); } else {
proceed(card, val); // Cho phép thực hiện tiếp
} } }
Các aspect con được cài đặt để kiểm chứng bất biến liên quan đến các thuộc tính được thừa kế withdrawalAmountPerDay và balanceAmount của các đối tượng của các lớp SilverATM và GoldATM có tên tương ứng và SilverATMVerifier và GoldATMVerifier. Aspect SilverATMVerifier có aspect cha là ATMcardVerifier và
aspect GoldATMVerifier có aspect cha là SilverATMVerifier. Trong hai aspect con này không cần phải khai báo lại các pointcut mà được thừa kế các pointcut từ aspect
cha ATMcardVerifier và chỉ cần cài đặt lại advice để kiểm tra xem joint point có được so khớp tại đối tượng của lớp tương ứng không. Mã cài đặt của aspect
SilverATMVerifier như sau:
public abstract aspect SilverATMVerifier extends ATMcardVerifier {
void around(ATMcard card, int val): verify_withdrawalAmount(card, val) {
Object sl = thisJoinPoint.getTarget(); String objName=sl.getClass().getName();
if(objName.equals("SilverATM") && val>3000) {
System.out.println("SilverATM.withdrawalAmountPerDay<=300 0");
} else {
proceed(card, val); // Cho phép thực hiện tiếp
}
void around(ATMcard card, int val): verify_balance(card, val){ Object sl = thisJoinPoint.getTarget();
String objName=sl.getClass().getName();
if(objName.equals("SilverATM") && val<-5000) {
System.out.println("SilverATM.balanceAmount>=-5000"); } else {
proceed(card, val); // Cho phép thực hiện tiếp
} } }
Và của aspect GoldATMVerifier như sau:
public aspect GoldATMVerifier extends SilverATMVerifier { void around(ATMcard card, int val):
verify_withdrawalAmount(card, val) { Object sl = thisJoinPoint.getTarget(); String objName=sl.getClass().getName(); if(objName.equals("GoldATM") && val>5000) {
System.out.println("GoldATM.withdrawalAmountPerDay <= 5000");
} else {
proceed(card, val); // Cho phép thực hiện tiếp
} }
void around(ATMcard card, int val): verify_balance(card, val){ Object sl = thisJoinPoint.getTarget();
String objName=sl.getClass().getName(); if(objName.equals("GoldATM") && val<-10000){
System.out.println("GoldATM.balanceAmount>=-10000"); } else {
} } }
Aspect GoldATMVerifier là aspect cụ thể do không còn aspect nào thừa kế nó và
advice của aspect này có quyền ưu tiên cao nhất. Khi thực hiện xong mà bất biến không bị vi phạm thì cả hai advice của hai aspect SilverATMVerifier và GoldATMVerifier đều trả quyền thực thi cho các advice có độ ưu tiên thấp hơn (hàm proceed() được gọi). Do vậy, tại các advice này chúng ta vẫn phải thực hiện việc kiểm xem joint point được so khớp tại đối tượng của lớp nào nhằm cài đặt chính xác mã kiểm chứng cho đối tượng phù hợp.