Monday, September 19, 2005

Implement Domain Validatation ด้วย "AspectJ Introduction"

เวลา Design Application เรามักต้องตัดสินใจว่า
จะ implement Validation Logic ไว้ที่ Layer ไหนดี

RubyOnRails implement Validation Logic ไว้ที่ Model
(domain layer)
struts (รวมทั้ง MVC อื่นๆของ java) provide Validation Logic
ไว้ที่ Presentation Layer

ข้อดีของการ provide Validation Logic ไว้ที่ domain
ก็คือ กรณีที่มี Presentation Layer หลายๆแบบ
validation logic ก็จะ share อยู่ที่เดียว ไม่กระจัดกระจาย

วันนี้เราจะลองเอา AspectJ ซึ่งเป็น AOP
มาลองทำ Validation แบบ Mixin บ้าง
สมมติเรามี Class Person
public class Person {

private String name;
private int age;

public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

}

Note: Person Class ที่เราเขียน จะเป็น POJO เพียวๆเลย
ไม่มี business logic อะไรอยู่ในนั้นเลย


ออกแบบ Validataion Framework ให้มี Class ดังนี้



เป้าหมายที่เราต้องการ ก็คือ เราจะเขียน logic ในส่วนของการ
validate สำหรับ Person แยกไว้เป็นอีก file หนึ่ง (เรียก Aspect)
แล้วใช้ AspectJ ทำการ mix Person class กับ Aspect ที่เขียนไว้เข้าด้วยกัน

สร้าง Aspect ที่ชื่อ PersonValidate.aj
public aspect PersonValidate {
declare parents: Person implements Validatable;

public Errors Person.validate() {
Errors errs = new Errors();
if (this.getName() == null ||
this.getName().length() == 0) {
errs.addError("name", "name must not be empty");
}
if (this.getAge() <= 0) {
errs.addError("age", "age must not be negative or zero");
}
return errs;
}

}

ใน PersonValidate.aj จะมีการ declare parents: Person implements Validatable;
การสั่งแบบนี้ ก็คือเราจะกำหนดให้ Person Class implement Interface ที่ชื่อ Validatable
จากนั้นก็กำหนด method validate ให้กับ Person class
(method validate เป็น method ที่ declare ไว้ใน Validatable interface)
สังเกตุดูใน code จะเห็นว่าเราสามารถใช้ this ในการอ้างถึง person instance
ที่ถูก modify ได้

ทดลอง Run
    public static void main(String[] args) {
Person p = new Person();
p.setAge(-1);

Validatable vt = (Validatable) p;
Errors err = vt.validate();

for (int i = 0; i < err.size(); i++) {
System.out.println(err.getError(i));
}
}


ได้ผลลัพท์ดังนี้

name:name must not be empty
age:age must not be negative or zero


จะเห็นได้ว่า แนวคิดนี้ ดูน่าสนใจทีเดียว (ในแง่ Architecture)
แต่ความคิดนี้ยังไม่ได้ทดลองทำจริงนะ ก็เลยยังไม่รู้ว่าจะเกิดโทษ
หรือเกิดประโยชน์อย่างไรบ้าง

Related link from Roti

No comments: