ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ
PHẠM ĐÌNH PHONG
NGHIÊN CỨU VỀ
KIỂM CHỨNG BẤT BIẾN CỦA ĐỐI TƯỢNG
SỬ DỤNG LẬP TRÌNH HƯỚNG KHÍA CẠNH
Ngành: Công nghệ thông tin
Chuyên ngành: Công nghệ phần mềm
Mã số: 60 48 10
LUẬN VĂN THẠC SĨ
NGƯỜI HƯỚNG DẪN KHOA HỌC: PGS. TS. Nguyễn Việt Hà
Hà Nội – 2010
ii
Lời cảm ơn
Với lòng biết ơn sâu sắc, em xin chân thành cảm ơn thầy giáo PGS. TS. Nguyễn
Việt Hà, người đã trực tiếp định hướng đề tài và tận tình hướng dẫn em hoàn thành luận
văn này. Em cũng chân thành cảm ơn thầy TS. Phạm Ngọc Hùng đã có những nhận xét,
đánh giá trong quá trình hoàn thiện luận văn.
Em xin được bày tỏ lòng biết ơn đối với các thầy giáo, cô giáo Khoa Công nghệ
thông tin Trường Đại học Công nghệ đã tận tình chỉ bảo, giảng dạy em suốt thời gian
học tại trường cũng như việc hoàn thành luận văn này.
Cuối cùng, xin được bày tỏ tình cảm tới những người thân trong gia đình, các bạn
bè trong tập thể lớp Cao học K15T2, K15T3 và K15CNPM đã động viên, hỗ trợ em về
mọi mặt.
Em xin chân thành cảm ơn!
Hà Nội, tháng 09 năm 2010
Phạm Đình Phong
iii
Lời cam đoan
Tôi xin cam đoan rằng, ngoại trừ các nội dung được trích từ tài liệu tham khảo
hoặc các công trình khác như đã ghi rõ trong luận văn, các kết quả nêu trong luận văn
này là do chính tôi thực hiện.
Hà Nội, tháng 09 năm 2010
Phạm Đình Phong
iv
MỤC LỤC
Lời cảm ơn ii
Lời cam đoan iii
MỤC LỤC iv
Danh mục bảng biểu vi
Danh mục hình vẽ vii
Danh mục ký hiệu, từ viết tắt viii
MỞ ĐẦU 1
Chương 1 – Lập trình hướng khía cạnh 4
1.1. Giới thiệu 4
1.2. Các vấn đề tồn tại trong lập trình hướng đối tượng 5
1.2.1. Các mối quan tâm của hệ thống 5
1.2.2. Giải quyết các mối quan tâm cắt ngang bằng OOP 7
1.2.3. Các vấn đề gặp phải khi thực thi các mối quan tâm cắt ngang bằng OOP8
1.3. Lập trình hướng khía cạnh 10
1.3.1. Lịch sử hình thành 10
1.3.2. Cú pháp của AOP và mô hình lập trình 11
1.3.3. Quản lý các mối quan tâm bằng lập trình hướng khía cạnh 12
1.3.4. Đan kết 13
1.3.5. Phương pháp lập trình hướng khía cạnh 14
1.3.6. Lợi ích của lập trình hướng khía cạnh 15
1.3.7. Nhược điểm của phương pháp lập trình hướng khía cạnh 17
1.3.8. Các công cụ AOP 18
1.4. AspectJ 19
1.4.1. Thực thi cắt ngang 19
1.4.2. Joint Point 20
1.4.3. Pointcut 22
1.4.4. Advice 26
1.4.5. Introduction 29
1.4.6. Aspect 30
1.5. Kết luận 33
Chương 2 - Công cụ kiểm chứng mô hình Java PathFinder 34
2.1. Giới thiệu 34
2.2. Công cụ kiểm chứng mô hình Java PathFinder 34
2.2.1. Lịch sử của Java PathFinder 35
2.2.2. Các thành phần của Java PathFinder 35
2.2.3. Những gì có thể được kiểm chứng bởi Java PathFinder 37
2.2.4. Kiểm chứng mô hình trong Java PathFinder 37
2.3. Các đề án mở rộng của Java PathFinder 40
2.4. Kết luận 41
Chương 3 – Kiểm chứng bất biến của chương trình Java sử dụng lập trình hướng khía
cạnh 42
3.1. Đặt vấn đề 42
3.2. Ngôn ngữ mô hình hóa thống nhất UML 43
3.2.1. Thuộc tính 43
v
3.2.2. Liên kết 44
3.2.3. Thao tác 44
3.3. Ngôn ngữ ràng buộc đối tượng OCL 45
3.3.1. Biểu diễn biểu thức OCL 45
3.3.2. Bất biến (invariant) 46
3.4. Ví dụ minh họa 48
3.5. Kiểm chứng bất biến sử dụng AOP 50
3.6. Vấn đề kế thừa các bất biến ở lớp con 51
3.7. Kiểm chứng bất biến của lớp con có ràng buộc thay đổi so với lớp cha 55
3.8. Kiểm chứng bất biến liên quan đến các thuộc tính được thêm vào lớp con 60
3.9. Thực nghiệm 62
3.10. Kết luận 64
Chương 4 – Sinh tự động các ca kiểm thử bằng công cụ Java PathFinder 65
4.1. Tổng quan 65
4.2. Thực thi ký hiệu 65
4.3. Sinh tự động các ca kiểm thử bằng thực thi ký hiệu 67
4.4. Kiểm chứng bất biến bằng việc chèn khẳng định 71
4.4.1. Khẳng định trong Java và Java PathFinder 71
4.4.2. Xác định các bất biến 72
4.4.2.1. Đặt khẳng định trong đoạn mã 72
4.4.2.2. Kiểm tra bất biến trong phương thức main 72
4.4.2.3. Bất biến như là một tiến trình (Invariant as a Thread) 74
4.4.3. So sánh phương pháp AOP và phương pháp chèn khẳng định 75
4.5. Kết quả thực nghiệm 76
4.5.1. Kết quả thực nghiệm sinh các ca kiểm thử tự động 76
4.5.2. Kết quả thực nghiệm kiểm chứng bất biến bằng chèn khẳng định 79
4.6. Kết luận 80
KẾT LUẬN 81
TÀI LIỆU THAM KHẢO 83
vi
Danh mục bảng biểu
Bảng 1.1. So sánh giữa aspect và lớp
Bảng 3.1. Một số kết quả thực nghiệm
vii
Danh mục hình vẽ
Hình 1.1. Các mối quan tâm trong một hệ thống
Hình 1.2. Thực thi các mối quan tâm cắt ngang bằng OOP
Hình 1.3. Chồng chéo mã nguồn
Hình 1.4. Dàn trải mã nguồn
Hình 1.5. Sự khác nhau giữa biên dịch chương trình thông thường và có aspect
Hình 1.6. Mối quan hệ giữa các thuật ngữ AOP
Hình 1.7. Thực thi các mối quan tâm cắt ngang bằng AOP
Hình 1.8. Các giai đoạn phát triển AOP
Hình 1.9. Ví dụ về định nghĩa pointcut
Hình 2.1. Sự bố trí các tầng của JPF
Hình 2.2. Các thành phần của JPF
Hình 2.3. Bùng nổ không gian trạng thái do sự đan xen giữa các luồng
Hình 3.1. Biểu diễn các ràng buộc trên sơ đồ UML
Hình 3.2. Ví dụ biểu đồ lớp của hệ thống card ATM
Hình 3.3. Quy trình kiểm chứng bất biến
Hình 4.1. Thực thi ký hiệu
viii
Danh mục ký hiệu, từ viết tắt
Từ viết tắt
Thuật ngữ
Ý nghĩa
AOP
Aspect-Oriented Programming
Lập trình hướng khía cạnh
API
Application Programming
Interface
Giao diện lập trình ứng dụng
ASCII
American Standard Code for
Information Interchange
Bộ mã chuẩn cho trao đổi thông tin
của Mỹ
AWT
Abstract Window Toolkit
Bộ công cụ đồ họa độc lập nền tảng
của Java
CTW
Compile-time Weaving
Đan kết lúc biên dịch
Eclipse
Bộ công cụ phát triển phần mềm
IBM
International Business Machines
Corp
Một trong những nhà sản xuất máy
tính lớn nhất thế giới
JDK
Java Development Kit
Bộ phát triển ứng dụng Java
JPF
Java PathFinder
Bộ công cụ kiểm chứng mô hình
cho ngôn ngữ Java
JVM
Java Virtual Machine
Máy ảo Java
LTW
Load-time Weaving
Đan kết lúc nạp chương trình
MJI
Model Java Interface
Giao diện Java mẫu
OCL
Object Constraint Language
Ngôn ngữ ràng buộc đối tượng
OOP
Object-Oriented Programming
Lập trình hướng đối tượng
RTW
Run-time Weaving
Đan kết lúc thực thi
SPIN
Simple Promela INterpreter
Công cụ thông dịch ngôn ngữ
Promela (trong kiểm chứng mô
hình)
SUT
System Under Test
Hệ thống được kiểm thử
Syntropy
Một phương pháp phân tích và thiết
kế hướng đối tượng thế hệ thứ hai
UML
Unified Modeling Language
Ngôn ngữ mô hình hóa thống nhất
VM
Virtual Machine
Máy ảo
XML
eXtensible Markup Language
Ngôn ngữ đánh dấu mở rộng
1
MỞ ĐẦU
Những năm gần nay, với sự phát triển của phương pháp lập trình hướng đối
tượng (OOP) [1, 2, 12] đã mang lại nhiều bước tiến mới cho lập trình nói chung và đưa
ngành Công nghệ phần mềm lên một bước phát triển mới. Ưu điểm lớn nhất của lập
trình hướng đối tượng là một hệ thống phần mềm được xây dựng bởi tập các lớp rời
rạc. Mỗi lớp có nhiệm vụ hoàn toàn xác định, các nhiệm vụ của nó được vạch ra một
cách rõ ràng. Trong một ứng dụng hướng đối tượng, các lớp cộng tác với nhau để đạt
được mục tiêu chung của ứng dụng. Tuy nhiên, có các phần của một hệ thống không
chỉ gánh nhiệm vụ giới hạn trong một lớp, chúng cắt ngang toàn bộ hệ thống và ảnh
hưởng đến nhiều lớp. Đó chính là sự đan nhau phức tạp giữa các thành phần bên trong
ứng dụng. Bên cạnh đó, tính tĩnh trong cách tiếp cận hướng đối tượng không cho phép
phần mềm thích ứng với những thay đổi mới đáp ứng yêu cầu người dùng. Một hướng
tiếp cận mới trong việc phát triển phần mềm là lập trình hướng khía cạnh (AOP:
Aspect-Oriented Programming) [10, 22, 3]. Hướng tiếp cận này còn khá mới mẻ
nhưng hứa hẹn những lợi điểm giải quyết được những yêu cầu có tính đan xen phức
tạp, đồng thời mang lại cho phần mềm khả năng thay đổi và bổ sung yêu cầu mới sau
khi đã hoàn chỉnh hay thậm chí đã đưa vào sử dụng.
Ngôn ngữ mô hình hóa thống nhất (Unified Modelling Language - UML [4])
được chấp nhận rộng rãi như là một chuẩn cho phân tích và thiết kế hướng đối tượng.
Việc biểu diễn và mô hình hóa cấu trúc tĩnh của hệ thống hướng đối tượng được dùng
phổ biến trong các sơ đồ lớp UML. Tuy nhiên, không phải các cấu trúc chi tiết nào
cũng có thể được biểu diễn một cách dễ dàng trong một sơ đồ lớp. Ngôn ngữ ràng
buộc đối tượng (Object Constraint Language - OCL [29]), một phần của UML, là ngôn
ngữ dùng cho việc mô tả các ràng buộc thêm vào trên các mô hình hướng đối tượng.
Các ràng buộc OCL được sử dụng để mô tả các bất biến trên các lớp và các kiểu, các
tiền điều kiện và hậu điều kiện của các thao tác. Các ràng buộc OCL luôn luôn được
kết nối tới một mô hình hướng đối tượng UML. Một bất biến (invariant) là một ràng
buộc liên quan đến một lớp, kiểu hay giao diện trong một mô hình UML. Bất biến
được biểu diễn như một biểu thức lôgic giới hạn giá trị của một thuộc tính hay liên kết
hay nó có thể biểu diễn mối quan hệ giữa các giá trị của các thuộc tính, các liên kết.
Kết quả của biểu thức phải là đúng đối với tất cả các thể hiện của lớp được tham chiếu.
Giai đoạn đảm bảo chất lượng phần mềm ngày càng trở nên quan trọng. Trong
giai đoạn này, các đặc tả UML và các ràng buộc OCL đã được tạo ra bởi các nhà thiết
kế phần mềm, chương trình chính đã được cài đặt bởi các nhà phát triển phần mềm
dựa trên các đặc tả UML. Như vậy làm thế nào để kiểm chứng được bất biến của các
đối tượng được thể hiện bằng các ràng buộc OCL có bị vi phạm tại thời điểm thực thi
hay không. Sau khi nghiên cứu phương pháp AOP, chúng tôi thấy có thể sử dụng
2
phương pháp này để cài đặt các mã kiểm chứng để kiểm chứng các bất biến của các
phần mềm được thiết kế theo phương pháp hướng đối tượng dựa trên các ràng buộc
OCL đã được thiết kế. Đã có những nghiên cứu trước đó liên quan đến phương pháp
này [3, 23]. Theo đó, công việc kiểm chứng được tách biệt hoàn toàn khỏi chương
trình chính bằng cách tạo ra các aspect chứa mã kiểm chứng. Các aspect này sẽ được
đan tự động vào chương trình chính và khi chương trình được thực thi, công việc kiểm
chứng sẽ được thực hiện tự động. Tuy nhiên các nghiên cứu chưa xem xét việc kiểm
chứng bất biến cho các lớp con được kế thừa bên dưới. Chúng tôi quan tâm tới việc
xem xét các bất biến của các đối tượng theo quan hệ kế thừa, cụ thể là nghiên cứu
kiểm chứng bất biến liên quan đến các thuộc tính được thêm mới vào lớp con và bất
biến của lớp con có ràng buộc thay đổi so với lớp cha.
Việc kiểm thử tính đúng đắn của các phương thức cần có bộ dữ liệu làm đầu vào
cho các phương thức cần kiểm thử. Một bộ dữ liệu vào như vậy được gọi là một ca
kiểm thử (test case). Việc chọn các bộ dữ liệu như thế nào để có thể phủ toàn bộ các
đường thực thi có thể (possible execution path) là rất khó. Nếu có công cụ sinh tự động
các ca kiểm thử phủ toàn bộ các đường thực thi có thể thì ta có thể chứng minh tính
đúng đắn của phương thức thông qua các ca kiểm thử được sinh ra. Java PathFinder
(JPF) [19, 25, 30, 31] với phần mở rộng của nó là thực thi ký hiệu dùng để sinh tự
động các ca kiểm thử phủ được toàn bộ các đường thực thi có thể cho các phương thức
của các đối tượng trong chương trình được cài đặt bằng ngôn ngữ Java. Chúng tôi sử
dụng công cụ thực thi ký hiệu để sinh tự động các ca kiểm thử nhằm kiểm tra lại
phương pháp kiểm chứng bất biến bằng AOP.
Nội dung nghiên cứu: Tìm hiểu và nghiên cứu về kiểm chứng phần mềm, lập trình
hướng khía cạnh (Aspect Oriented Programming - AOP) và sử dụng AOP để kiểm
chứng bất biến của đối tượng bao gồm:
Nghiên cứu về lý thuyết kiểm chứng phần mềm, các phương pháp, công cụ
kiểm chứng phần mềm.
Nghiên cứu phương pháp lập trình hướng khía cạnh và AspectJ - một đặc tả
ngôn ngữ cho việc cài đặt các aspect bằng ngôn ngữ lập trình Java.
Mở rộng phương pháp sử dụng AOP để kiểm chứng các bất biến của đối
tượng trong chương trình Java tại thời điểm thực thi được đề xuất trong [23] bao gồm
kiểm chứng bất biến liên quan đến các thuộc tính được thêm mới vào ở lớp con và bất
biến của lớp con có ràng buộc thay đổi so với lớp cha.
Để kiểm tra tính đúng đắn của các phương thức cần có các ca kiểm thử làm
dữ liệu đầu vào. Do đó chúng tôi nghiên cứu công cụ kiểm chứng mô hình Java
PathFinder và phần mở rộng thực thi ký hiệu (Symbolic Execution) [15] của nó để
sinh tự động các ca kiểm thử cho các phương thức của các đối tượng trong chương
trình hướng đối tượng Java.
3
Sử dụng công cụ Java PathFinder để kiểm chứng bất biến được khai báo dưới
dạng các khẳng định (assertion) trong chương trình Java và so sánh với phương pháp
kiểm chứng bất biến sử dụng AOP.
Cấu trúc luận văn: Luận văn gồm các phần: Mở đầu, 4 chương, kết luận và tài liệu
tham khảo:
Chương 1 giới thiệu phương pháp lập trình hướng khía cạnh. Chúng tôi trình bày
quá trình hình thành phương pháp lập trình hướng khía cạnh, ưu điểm và nhược điểm
của nó đồng thời trình bày về AspectJ – một cài đặt phổ biến của AOP trên ngôn ngữ
lập trình hướng đối tượng Java.
Chương 2 trình bày tổng quan về công cụ kiểm chứng mô hình Java PathFinder
(JPF) và các mở rộng của nó.
Chương 3 trình bày và mở rộng kỹ thuật kiểm chứng bất biến của đối tượng trong
chương trình hướng đối tượng Java tại thời điểm thực thi sử dụng phương pháp AOP.
Chúng tôi trình bày kỹ thuật sử dụng AOP để kiểm chứng bất biến của đối tượng Java.
Phương pháp này đã có các nghiên cứu được công bố [23, 3] và chúng tôi mở rộng
xem xét các bất biến theo quan hệ kế thừa. Cụ thể là chúng tôi đề xuất kỹ thuật kiểm
chứng bất biến liên quan đến các thuộc tính được thêm vào lớp con và bất biến của lớp
con có ràng buộc thay đổi so với lớp cha.
Chương 4 trình bày phương pháp sử dụng công cụ thực thi ký hiệu là một mở
rộng của JPF để sinh các ca kiểm thử tự động cho các phương thức của đối tượng
trong chương trình hướng đối tượng Java nhằm mục đích kiểm tra lại phương pháp
kiểm chứng sử dụng AOP. Chương này cũng trình bày phương pháp kiểm chứng bất
biến được khai báo dưới dạng các khẳng định trong chương trình Java sử dụng JPF và
so sánh với phương pháp kiểm chứng bất biến sử dụng AOP. Một vài thực nghiệm của
thực thi ký hiệu và của kiểm chứng bất biến bằng việc chèn các khẳng định cũng được
trình bày.
4
Chương 1 – Lập trình hướng khía cạnh
1.1. Giới thiệu
Hệ thống phần mềm có thể được xem là một thể hiện kết hợp nhiều vấn đề. Một
hệ thống tiêu biểu có thể gồm nhiều dạng vấn đề như xử lý nghiệp vụ, hiệu suất, bảo
toàn dữ liệu, bảo mật, bẫy lỗi, … và còn có những vấn đề của quá trình phát triển hệ
thống như tính dễ quản lý, dễ bảo trì và phát triển. Trong việc thiết kế phần mềm, các
nhà thiết kế phần mềm thường tập chung sự quan tâm vào các chức năng chính, cơ bản
của hệ thống. Trong ứng dụng của các doanh nghiệp, đó chính là các logic nhiệp vụ cơ
bản. Ví dụ như trong ứng dụng quản lý nhgiệp vụ bảo hiểm, các mô-đun chức năng
chính được thiết kế cho việc quản lý các giao dịch bảo hiểm do khách hàng hoặc nhân
viên phòng nghiệp vụ thực hiện. Trong ứng dụng quản lý nhân sự, các mô-đun quản lý
chính là quản lý hồ sơ nhân viên, tính toán lương và các chế độ cho nhân viên. Trong
hai ứng dụng trên, các mô-đun xử lý nghiệp vụ chính có thể được thực hiện riêng rẽ
nhưng có những mối quan tâm liên quan đến nhiều mô-đun như tính năng lưu vết, xác
thực quyền hạn, truy cập cơ sở dữ liệu, bẫy lỗi, … Các tính năng đó là cần thiết đối với
mỗi mô-đun chính của hệ thống và dàn trải trên nhiều môđun của hệ thống. Các mối
quan tâm dàn trải trên nhiều mô-đun của hệ thống đó được gọi là các mối quan tâm cắt
ngang (cross-cutting concerns). Do vậy đối với mỗi mô-đun, lập trình viên ngoài việc
quan tâm đến những vấn đề cơ bản còn phải tính đến những mối quan tâm cắt ngang
và sự trộn lẫn nhiều đoạn mã để xử lý những yêu cầu khác nhau. Sự trộn lẫn nhiều
đoạn mã như vậy gọi là vấn đề đan nhau. Do vấn đề đan nhau có ở nhiều mô-đun nên
các đoạn xử lý liên quan cũng xuất hiện ở nhiều mô-đun. Những vấn đề này ảnh
hưởng đến vấn đề thiết kế và phát triển phần mềm như hệ thống khó xây dựng, khó
quản lý, phát triển và tái sử dụng kém.
Lập trình hướng đối tượng (Object-Oriented Programming - OOP) [1, 2, 12] là
phương pháp lập trình phổ biến nhất hiện nay được sử dụng để quản lý các mối quan
tâm nghiệp vụ chính, tuy nhiên phương pháp này chưa đủ mạnh để xử lý hiệu quả rất
nhiều các mối quan tâm cắt ngang hệ thống, đặc biệt là các ứng dụng phức tạp.
Phương pháp lập trình hướng khía cạnh (Aspect-Oriented Programming - AOP)
[10, 22, 3] là phương pháp lập trình mới cho phép chúng ta thực hiện các vấn đề riêng
biệt một cách linh hoạt và kết hợp chúng lại để tạo nên hệ thống sau cùng. AOP bổ
sung cho kỹ thuật lập trình hướng đối tượng bằng việc cung cấp một dạng mô-đun
khác bằng cách kéo các mối quan tâm cắt ngang vào một khối, đó chính là aspect. Với
AOP, ta có thể cài đặt các mối quan tâm cắt ngang hệ thống trong các aspect thay vì
dàn trải chúng trên các mô-đun nghiệp vụ chính liên quan. Quá trình bộ đan aspect
(weaver) kết hợp các mô-đun nghiệp vụ chính với các aspect thành hệ thống cuối cùng
5
được gọi là quá trình đan (weaving). Như vậy, AOP đã mô-đun hóa các mối quan tâm
cắt ngang một cách rõ ràng, tách biệt với các mô-đun nghiệp vụ chính giúp cho việc
thiết kế, thực thi và bảo trì hệ thống dễ dàng hơn và tốn ít chi phí, công sức. Các aspect
của hệ thống có thể thay đổi, thêm hoặc xóa lúc biên dịch và có thể tái sử dụng.
Lập trình hướng khía cạnh là kỹ thuật lập trình mới cho phép đóng gói những
hành vi liên quan đến nhiều đối tượng và rất có thể sẽ là bước phát triển kế tiếp trong
phương pháp lập trình. Tuy nhiên AOP không thay thế OOP mà nó là sự bổ sung cho
OOP, cho phép chúng ta giải quyết các bài toán phức tạp tốt hơn và hiệu quả hơn.
Trong các phần tiếp theo, chúng ta sẽ khảo sát những vấn đề mà lập trình hướng đối
tượng làm tốt và những vấn đề phát sinh từ các đối tượng và làm thế nào AOP có thể
lấp khoảng trống này. AspectJ [11, 13, 26], một cài đặt phổ biến của AOP trên ngôn
ngữ Java cũng được giới thiệu trong chương này.
1.2. Các vấn đề tồn tại trong lập trình hướng đối tượng
Phát triển phần mềm đã đi được một quãng đường khá dài. Khi sự hữu ích của
phát triển phần mềm được phát hiện, sự cải tiến nó đã trở nên bắt buộc để tìm kiếm các
kỹ thuật để mô hình hóa các bài toán của thế giới thực một cách hiệu quả hơn. Nhiều
năm trước, phương pháp luận chung cho việc giải quyết một bài toán là chia nó thành
các môđun chức năng nhỏ hơn và mỗi chức năng được cấu thành từ nhiều dòng lệnh.
Phương pháp luận này đã làm việc tốt nhưng một trạng thái hệ thống được điều khiển
bởi một số lượng lớn các biến toàn cục mà chúng có thể được thay đổi bởi bất kỳ dòng
lệnh nào trong ứng dụng. Sự xuất hiện của phương pháp luận hướng đối tượng kéo
trạng thái của hệ thống vào các đối tượng riêng lẻ, chúng có thể trở nên riêng tư và
được điều khiển thông qua các phương thức truy cập và logic.
Kỹ thuật OOP rất xuất xắc trong việc đóng gói các hành vi vào chủ thể lớp
(class), miễn là chúng riêng biệt. Tuy nhiên, trong các bài toán thực tế có những hành
vi dàn trải trên nhiều lớp. Trong hầu hết các ngôn ngữ lập trình hướng đối tượng
truyền thống như C++ [2] hay Java [1, 12] đều không hỗ trợ việc đóng gói các hành vi
dàn trải trên nhiều môđun, dẫn đến mã chương trình có thể nằm lẫn lộn, rải rác và khó
quản lý. Hiện tại, OOP được lựa chọn cho hầu hết các dự án phần mềm. Nó tập chung
vào giải quyết các nghiệp vụ chính nhưng nó không phải là phương pháp tốt để quản
lý các hành vi dàn trải trên nhiều mô-đun.
1.2.1. Các mối quan tâm của hệ thống
Sự chia tách các mối quan tâm là một nguyên lý cơ bản của kỹ nghệ phần mềm.
Nguyên lý này giúp quản lý tính phức tạp của phát triển phần mềm bằng việc khai báo,
đóng gói và khai thác các phần của phần mềm liên quan đến một mối quan tâm đặc
thù. Một mối quan tâm (concern) là một yêu cầu cụ thể hoặc một sự cân nhắc nào đó
cần phải được đưa ra nhằm thỏa mãn mục đích chung của toàn hệ thống. Một hệ thống
phần mềm là việc thực thi tập các mối quan tâm đó. Ví dụ trong một hệ thống quản lý
6
nghiệp vụ bảo hiểm bao gồm việc thực thi các mối quan tâm sau: quản lý khách hàng,
quản lý hợp đồng bảo hiểm, tính lãi suất cho các hợp đồng bảo hiểm có yếu tố tiết
kiệm, thực hiện chi trả bảo hiểm, tạo báo cáo, xác thực quyền hạn, lưu vết giao dịch,
… Bên cạnh các mối quan tâm của hệ thống, một dự án phần mềm cần chỉ ra được các
mối quan tâm khác liên quan đến toàn bộ các thuộc tính chất lượng của hệ thống như
tính dễ hiểu, dễ quản lý, dễ bảo trì và phát triển.
Các mối quan tâm được chia thành hai loại: mối quan tâm chính được cài đặt
chức năng chính của một mô-đun và mối quan tâm cắt ngang là yêu cầu ngoài, mức hệ
thống và dàn trải trên nhiều mô-đun. Một ứng dụng của một doanh nghiệp không
những quan tâm đến các mối quan tâm nghiệp vụ chính mà còn phải quan tâm đến các
mối quan tâm cắt ngang hệ thống như xác thực quyền hạn, lưu vết giao dịch, bẫy lỗi,
truy cập tài nguyên chung, đảm bảo tính toàn vẹn của giao dịch, … Tất cả các mối
quan tâm này đều cắt ngang một số mô-đun. Ví dụ như mối quan tâm về việc lưu vết
giao dịch liên quan đến tất cả các môđun giao dịch chính, mối quan tâm về truy cập dữ
liệu liên quan đến các mô-đun có truy xuất cơ sở dữ liệu, mối quan tâm về xác thực
quyền hạn liên quan đến các mô-đun có yêu cầu về quản lý quyền truy cập. Hình 1.1
minh họa việc thực thi các mô-đun trong một hệ thống chứa cả các mối quan tâm mức
hệ thống và các mối quan tâm nghiệp vụ. Ở đây, một hệ thống được mô tả như một sự
tổng hợp của nhiều mối quan tâm. Hệ thống trở nên chồng chéo lên nhau bởi các kỹ
thuật cài đặt hiện tại, chính vì thế, sự độc lập giữa các mối quan tâm không được đảm
bảo.
Hình 1.1. Các mối quan tâm trong một hệ thống.
7
1.2.2. Giải quyết các mối quan tâm cắt ngang bằng OOP
Trong quá trình phát triển phần mềm các nhà phát triển thường xác định các mối
quan tâm và sau đó chia tách chúng cho các nhóm phát triển khác nhau để mô-đun hóa
chúng. Có những trở ngại lớn cho các nhóm phát triển khi mô-đun hóa các mối quan
tâm là làm sao xử lý hiệu quả các mối quan tâm cắt ngang hệ thống. Trong thực tế,
phương pháp OOP thường được sử dụng để mô-đun hóa các mối quan tâm của một hệ
thống phần mềm. Tuy nhiên, thực tế thì, mặc dù OOP giải quyết rất tốt trong việc mô-
đun hóa các mối quan tâm nghiệp vụ chính nhưng lại gặp khó khăn trong việc mô-đun
hóa các mối quan tâm cắt ngang hệ thống.
Trong OOP, các mô-đun chính có thể được kết nối lỏng với nhau thông qua giao
diện, nhưng không dễ gì làm việc này với các mối quan tâm cắt ngang hệ thống. Lý do
chính là một mối quan tâm được thực thi thành hai phần: Phần phía server (phần phục
vụ) và phần phía client (phần được phục vụ). OOP mô-đun hóa phần client khá tốt
bằng các lớp và các giao diện. Tuy nhiên, ở phía server, một mối quan tâm lại là một
loại cắt ngang hệ thống, bao gồm các yêu cầu gửi đến server, dàn trải trên các client.
Hình 1.2. Thực thi các mối quan tâm cắt ngang bằng OOP.
Xét một ví dụ điển hình về việc thực thi một mối quan tâm cắt ngang hệ thống
trong OOP: Một mô-đun lưu vết cung cấp các dịch vụ thông qua một giao diện trừu
tượng. Việc sử dụng giao diện nới lỏng kết nối giữa các client và việc thực thi các giao
diện. Các client sử dụng các dịch vụ lưu vết thông qua giao diện dành cho hầu hết các
phần không quan tâm đến chi tiết cài đặt mà họ đang sử dụng. Khi có bất cứ thay đổi
nào đến các cài đặt mà chúng đang sử dụng sẽ không yêu cầu thay đổi đến bản thân
các client. Tương tự như thế, việc thay thế sự thực thi lưu vết bằng một sự thực thi
khác chỉ là vấn đề về việc khởi tạo đúng loại thực thi. Kết quả là một sự thực thi về lưu
vết có thể được chuyển đổi với sự thực thi khác với ít hoặc không thay đổi cho các
8
mô-đun client riêng lẻ. Tuy nhiên, trong cấu hình này, các client vẫn phải chứa các
đoạn mã để gọi các API. Những lời gọi này cần phải có trong tất cả các mô-đun có yêu
cầu cần lưu vết và được trộn lẫn với các đoạn mã dành cho logic nghiệp vụ chính.
Hình 1.2 minh họa cách thực thi mối quan tâm lưu vết trong một hệ thống phần
mềm quản lý nghiệp vụ bảo hiểm sử dụng các kỹ thuật truyền thống như OOP. Thậm
chí khi sử dụng mô-đun lưu vết được thiết kế tốt đưa ra API trừu tượng và che giấu chi
tiết về việc định dạng và phân lớp các thông điệp lưu vết, thì mỗi mô-đun client như
mô-đun Subscribing, Claim hay Database đều phải chứa các đoạn mã để triệu gọi API
lưu vết. Kết quả tổng thể là gây ra sự lộn xộn, chồng chéo giữa các mô-đun cần lưu vết
và bản thân các mô-đun lưu vết.
1.2.3. Các vấn đề gặp phải khi thực thi các mối quan tâm cắt ngang bằng OOP
Khi thực thi các mối quan tâm cắt ngang bằng phương pháp OOP, hệ thống sẽ
gặp phải một số vấn đề trong đó có hai vấn đề chính là sự chồng chéo mã nguồn và
dàn trải mã nguồn.
Chồng chéo mã nguồn (Code tangling): Các mô-đun trong hệ thống có thể
đồng thời phải thực hiện nhiều yêu cầu khác nhau. Ví dụ như trong quá trình phát triển
một mô-đun nào đó, ngoài việc đảm bảo yêu cầu chính của mô-đun đó, lập trình viên
luôn phải tính tới các mối quan tâm khác như hiệu năng, đồng bộ, an ninh, lưu vết, lưu
trữ, Các mối quan tâm này làm cho việc xuất hiện rất nhiều loại mã chương trình của
các mối quan tâm khác nhau trong quá trình cài đặt mô-đun. Hiện tượng này gọi là
chồng chéo mã nguồn. Hình 1.3 minh họa vấn đề chồng chéo mã nguồn do sự thực thi
của nhiều mối quan tâm trên cùng một mô-đun.
Hình 1.3. Chồng chéo mã nguồn.
Dàn trải mã nguồn (Code scattering): Mã nguồn của các yêu cầu mức hệ
thống (an ninh, lưu vết, lưu trữ, ) được cài đặt ở trong rất nhiều mô-đun. Ví dụ như
chức năng lưu vết được cài đặt ở tất các các mô-đun quan trọng cần lưu vết. Như vậy
việc cài đặt mã nguồn cho một mối quan tâm bị xé nhỏ vào rất nhiều mô-đun khác
9
nhau. Hiện tượng này gọi là dàn trải mã nguồn. Hình 1.4 minh họa vấn đề dàn trải mã
nguồn do đặt nhiều đoạn mã giống nhau trong nhiều mô-đun khác nhau nhằm thực thi
một chức năng nào đó. Ở đây, trong ví dụ hệ thống quản lý nghiệp vụ bảo hiểm, nhiều
mô-đun trong hệ thống phải chứa đoạn mã để đảm bảo rằng những người dùng hợp lệ
mới có thể truy cập các các chức năng nghiệp vụ của hệ thống.
Hình 1.4. Dàn trải mã nguồn.
Với các vấn đề đã phân tích ở trên, quá trình phát triển phần mềm sẽ bị ảnh
hưởng với một số vấn đề sau:
Ánh xạ giữa các mối quan tâm và cài đặt kém: Việc đồng thời cài đặt nhiều
mối quan tâm cũng gây ra hiệu ứng làm giảm thiểu khả năng tư duy ánh xạ giữa một
mối quan tâm và mã nguồn cài đặt của nó cho lập trình viên cũng như người kiểm
duyệt mã nguồn.
Hiệu suất làm việc thấp: Việc đồng thời cài đặt nhiều mối quan tâm làm cho
lập trình viên phải phân tán tư tưởng vào nhiều mối quan tâm một lúc, giảm hiệu suất
làm việc.
Khả năng sử dụng lại mã nguồn kém: Một mô-đun thực tế đã cài đặt rất nhiều
mối quan tâm một lúc, nếu như hệ thống khác có nhu cầu sử dụng chức năng tương tự
có thể chưa chắc đã sử dụng lại mô-đun này do nó còn phụ thuộc vào các mối quan
tâm khác.
Chất lượng mã nguồn thấp: Việc chồng chéo mã nguồn trong quá trình cài đặt
sẽ gây ra những vấn đề tiềm ẩn mà lập trình viên có thể không phát hiện ra được khi
lập trình, do sự chú ý của mình bị ảnh hưởng bởi quả nhiều mối quan tâm.
10
Khó bảo trì hệ thống: Việc xây dựng hệ thống tại thời điểm nào đó thường bị
giới hạn trong một khung nhìn với những yêu cầu cụ thể nào đó, thể hiện ở các mối
quan tâm hiện có của hệ thống. Nếu như trong tương lai có sự thay đổi nào đó cần bổ
sung vào hệ thống, do việc cài đặt không được mô-đun hóa nên việc sửa đổi sẽ làm
ảnh hưởng tới rất nhiều mô-đun, có thể gây ra những sửa đổi không đồng bộ và không
thống nhất với nhau. Vì thế đòi hỏi thêm chí phí và thời gian để kiểm thử và đảm bảo
việc thay đổi trên là không gây ra lỗi.
1.3. Lập trình hướng khía cạnh
1.3.1. Lịch sử hình thành
Lập trình hướng khía cạnh (AOP) là một tiếp cận thiết kế phần mềm được phát
minh tại trung tâm nghiên cứu Xerox Palo Alto trong những năm 1990. Nó kế thừa các
kết quả của các phương pháp lập trình khác như lập trình tự sinh (generative
programming), siêu lập trình (meta-programming), lập trình tự điều chỉnh (reflective
programming), lập trình có khả năng thích ứng (adaptive programming), lập trình
hướng chủ đề (subject-oriented programming), lập trình có mục đích (intentional
programming), … Mục đích của AOP là để các nhà thiết kế và các nhà phát triển tách
các mối quan tâm cắt ngang mà một hệ thống phần mềm gặp phải tốt hơn. Các mối
quan tâm cắt ngang là các phần tử của một hành vi hệ thống không được xác định một
cách dễ dàng đối với các thành phần cụ thể trong một kiến trúc ứng dụng. Các mối
quan tâm cắt ngang thông thường là xử lý lỗi, các kiểm tra bảo mật, lưu vết các sự
kiện, xử lý giao dịch, … Mỗi thành phần trong ứng dụng phải chứa mã đặc trưng cho
mỗi mối quan tâm cắt ngang, tạo ra mã của thành phần phức tạp hơn và khó thay đổi
hơn.
Hình 1.5. Sự khác nhau giữa biên dịch chương trình thông thường và có aspect
Để xác định các mối quan tâm cắt ngang, AOP cũng cấp các kỹ thuật cho sự nhận
dạng có hệ thống, sự chia tách, sự biểu diễn và kết cấu. Mỗi quan tâm cắt ngang được
đóng gói trong các mô-đun riêng gọi là các aspect. Trong quá trình thực thi, các aspect
11
được đan kết vào chương trình thực thi để thực thi các mối quan tâm cắt ngang hệ
thống.
1.3.2. Cú pháp của AOP và mô hình lập trình
Cắt ngang là một kỹ thuật AOP cho phép nhận dạng các mối quan tâm và cấu
trúc chúng vào trong các mô-đun bằng cách chúng có thể được triệu gọi tại các điểm
khác nhau thông qua ứng dụng. Có hai loại cắt ngang, tĩnh và động. Cắt ngang động
sửa đổi hành vi thực thi của một đối tượng bằng việc đan kết hành vi mới tại các điểm
quan tâm cụ thể. Cắt ngang tĩnh thay thế cấu trúc tĩnh của một thành phần bằng việc
xen thêm các phương thức và các thuộc tính tại thời điểm thực thi. Các cấu trúc ngôn
ngữ cơ bản và cú pháp được sử dụng để khai báo cắt ngang trong AOP như sau:
Joint point là một điểm thực thi có thể nhận dạng trong một chương trình. Nó
có thể là một lời gọi tới một phương thức hay một lệnh gán cho một thuộc tính của đối
tượng. Các joint point là quan trọng, chúng là nơi mà các hành vi của aspect được đan
kết vào trong chương trình.
Pointcut là một cấu trúc chương trình lựa chọn ra một nhóm các join point và
tập hợp ngữ cảnh tại các join point này. Hay nói cách khác, pointcut nhận dạng một
joint point trong chương trình mà tại đó một mối quan tâm cắt ngang cần được áp
dụng. Ví dụ như, một pointcut có thể lựa chọn một join point là lời gọi tới một phương
thức, nó cũng có thể nắm bắt ngữ cảnh của phương thức đó, chẳng hạn như đối tượng
đích chứa phương thức được gọi và các tham số của phương thức đó. Pointcut dùng để
chỉ ra các quy tắc đan còn join point là các vị trí thỏa mãn các quy tắc đó.
Ví dụ sau khai báo một pointcut khi phương thức setValue của lớp Stock được
gọi:
pointcut log(String msg): args(msg) &
execution(void Stock.setValue(float));
Advice là một đoạn mã thực thi logic một mối quan tâm cắt ngang. Nó được
thực thi khi một pointcut cụ thể được đạt tới. Advice có thể được thực thi trước (before
advice), sau (after advice) hoặc “xung quanh” (around advice) join point.
Ví dụ một before advice được cài đặt trong AspectJ:
before (String msg): log(msg){
//Đoạn mã thực thi
}
Introduction là chỉ thị cắt ngang có thể tạo các thay đổi tĩnh đối với các thành
phần ứng dụng. Một introduction có thể tạo ra các thay đổi tĩnh cho các mô-đun mà
không ảnh hưởng trực tiếp đến các hành vi của chúng. Ví dụ, một instruction có thể
thêm một phương thức hoặc một trường vào một lớp trong ứng dụng.
12
Aspect trong AOP tương ứng với một lớp trong lập trình hướng đối tượng. Nó
đóng gói các pointcut, các advice và các intruction.
Ví dụ một aspect được cài đặt bằng AspectJ:
public aspect LoggingModule {
pointcut log(String msg):args(msg) &
execution(void Stock.setValue(float));
before (String msg): log(msg){
//Đoạn mã thực thi
}
}
Hình 1.6. Mối quan hệ giữa các thuật ngữ AOP
1.3.3. Quản lý các mối quan tâm bằng lập trình hướng khía cạnh
Với việc sử dụng các kỹ thuật thiết kế thông thường, một mối quan tâm cắt ngang
có thể được mô-đun hóa bằng việc sử dụng một giao diện để đóng gói sự thực hiện
mối quan tâm từ việc triệu gọi các thành phần phía client. Mặc dù giao diện làm giảm
sự móc nối giữa các client và sự thực thi mối quan tâm, các client vẫn cần mã nhúng
để triệu gọi các phương thức giao diện từ bên trong logic nghiệp vụ.
Với thiết kế và lập trình hướng khía cạnh, mỗi mối quan tâm cắt ngang được cài
đặt một cách riêng rẽ trong một thành phần là aspect. Aspect định nghĩa các điểm thực
thi trong các thành phần phía client đòi hỏi sự thực hiện mối quan tâm cắt ngang. Đối
với mỗi điểm thực thi, aspect định nghĩa các hành vi cần thiết để thực hiện hành vi của
aspect, ví dụ như gọi một API lưu vết. Trong hình 1.7, mối quan tâm cắt ngang là việc
13
lưu vết sự thực thi các mô-đun Subscribing, Claim và Database được cài đặt trong một
aspect là Logging aspect. Tiếp đó, Logging aspect có các lời gọi API tới Logging
module để thực thi các phương thức cần thiết. Trong quá trình thực thi ứng dụng,
Logging aspect được đan tự động vào các mô-đun nghiệp vụ chính để thực hiện việc
lưu vết giao dịch. Bộ phận phát triển các mô-đun Subscribing, Claim và Database
không cần quan tâm đến việc thực thi việc lưu vết trong quá trình phát triển.
Hình 1.7. Thực thi các mối quan tâm cắt ngang bằng AOP.
Quan trọng hơn là các mô-đun phía client không chứa bất kỳ mã để triệu gọi sự
thực thi aspect nào. Điều này dẫn đến các thành phần phía client không bị xen lẫn bởi
các lời gọi để thực thi một hoặc nhiều mối quan tâm.
Việc sử dụng một aspect được xác định theo một quy tắc nhất định gọi là quy tắc
đan. Các quy tắc đan là đầu vào cho một tiện ích lập trình gọi là bộ đan. Một bộ đan
kết hợp mã ứng dụng với các aspect để tạo ra hệ thống cuối cùng. Các ngôn ngữ lập
trình hướng khía cạnh như AspectJ cung cấp các công cụ đan kết và vì thế các ngôn
ngữ AOP và các công cụ là cần thiết để thực hiện hiệu quả các thiết kế hướng khía
cạnh.
1.3.4. Đan kết
Việc thực hiện một thiết kế hướng khía cạnh đòi hỏi sự hỗ trợ của ngôn ngữ lập
trình để thực thi các aspect riêng lẻ. Ngôn ngữ cũng định nghĩa các luật cho việc đan
kết một thực thi của aspect với toàn bộ mã chương trình. Việc đan kết có thể tuân theo
một số chiến lược:
1) một bộ tiền xử lý mã nguồn đặc biệt được thực thi trong qua trình biên dịch.
14
2) một bộ hậu xử lý vá các tệp nhị phân.
3) một trình biên dịch nhận biết AOP sinh ra các tệp nhị phân được đan kết.
4) đan kết lúc nạp (load-time weaving – LTW): ví dụ, trong Java việc đan kết
advice liên quan bằng việc nạp từng lớp advice vào trong JVM.
5) đan kết lúc thực thi (run-time weaving – RTW): bằng việc chặn từng join
point tại thời điểm thực thi và thực thi tất cả các advice liên quan.
Hầu hết các ngôn ngữ AOP hỗ trợ việc đan kết lúc biên dịch (CTW) sử dụng một
trong ba tùy chọn đầu. Trong Java, trình biên dịch sinh ra các tệp lớp nhị phân Java
chuẩn mà bất kỳ JVM chuẩn nào cũng có thể thực thi. Sau đó các tệp .class được sửa
đổi dựa trên các aspect đã được định nghĩa. CTW không phải lúc nào cũng là lựa chọn
tốt và đôi khi không khả thi (ví dụ với Java Server Page). LTW đưa ra giải pháp tốt
hơn và mềm dẻo hơn. Trong Java, LTW đòi hỏi trình nạp JVM để có thể biến đổi các
lớp lúc thực thi. JDK v5.0 hỗ trợ tính năng này thông qua một kỹ thuật chuẩn đơn
giản. LTW phải xử lý mã bytecode của Java lúc thực thi và tạo các cấu trúc dữ liệu
biểu diễn bytecode của một lớp cụ thể. Quá trình xử lý này có thể diễn ra chậm. Một
khi tất cả các lớp được nạp, LTW không có ảnh hưởng gì đến tốc độ thực thi của ứng
dụng. AspectJ [11, 13, 26], JBoss AOP [27] và AspectWerkz [28] hiện hỗ trợ LTW.
RTW là một lựa chọn tốt nếu các aspect phải có hiệu lực lúc đang chạy. Tuy nhiên,
như LTW, RTW có thể có những nhược điểm về mặt hiệu suất tại thời điểm thực thi
trong khi các aspect đang được đan kết.
1.3.5. Phương pháp lập trình hướng khía cạnh
Hiện nay phương pháp lập trình hướng khía cạnh đang được quan tâm phát triển
và đang dần được hoàn thiện. Phương pháp này không phải thay thế các phương pháp
lập trình truyền thống mà là bổ sung và làm phong phú thêm phương pháp lập trình
truyền thống. AOP cung cấp một giải pháp cho việc pháp triển các hệ thống bằng việc
tách các mối quan tâm cắt ngang thành các mô-đun và ghép nối lỏng các mô-đun này
vào các mối quan tâm nghiệp vụ chính của hệ thống. Về cơ bản quá trình phát triển
phần mềm theo AOP gồm có 3 bước sau đây:
1) Phân tích các yêu cầu để xác định vấn đề chung và vấn đề đan nhau: trong
bước này ta sử dụng phương pháp phân tích và thiết kế hướng khía cạnh (Aspect-
Oriented Analyis and Design) để phân tích các yêu cầu của bài toán nhằm tách các mối
quan tâm nghiệp vụ chính và mối quan tâm cắt ngang hệ thống. Sau bước này ta thu
được bản phân tích mà các mối quan tâm nghiệp vụ chính và các mối quan tâm cắt
ngang được tách riêng.
2) Xây dựng thể hiện từng vấn đề riêng biệt: sau khi các mối quan tâm cắt ngang
được tách ra khỏi các mối quan tâm nghiệp vụ chính thì ta có thể dùng phương pháp
lập trình truyền thống như lập trình hướng thủ tục hoặc lập trình hướng đối tượng để
15
cài đặt các mối quan tâm nghiệp vụ chính, còn các mối quan tâm cắt ngang thì được
cài đặt trong một aspect theo quy tắc mà công cụ AOP được sử dụng quy định. Như
vậy, mối quan tâm nghiệp vụ chính được xây dựng độc lập với các mối quan tâm cắt
ngang.
Hình 1.8. Các giai đoạn phát triển AOP
3) Tổng hợp các thể hiện: sau khi các mối quan tâm nghiệp vụ chính và các mối
quan tâm cắt ngang được cài đặt một các riêng rẽ, để hệ thống có thể hoạt động được
thì các mối quan tâm cần phải được kết hợp theo một số quy tắc nào đó. Quá trình kết
hợp này gọi là quá trình tích hợp hay quá trình đan được thực hiện bằng cách sử dụng
các quy tắc đan. Sau quá trình đan ta nhận được hệ thống cuối cùng mà các mối quan
tâm nghiệp vụ chính và mối quan tâm cắt ngang đã được đan kết với nhau để thực hiện
mục tiêu theo yêu cầu. Ví dụ một luật tích hợp: “Tất cả các hoạt động của hệ thống cần
phải được lưu vết lại” sẽ được cài đặt trên một ngôn ngữ AOP nào đó để chỉ ra các quy
tắc đan. Như vậy, mối quan tâm lưu vết sẽ được bộ đan tích hợp vào các mô-đun
nghiệp vụ theo đúng quy tắc chỉ ra.
1.3.6. Lợi ích của lập trình hướng khía cạnh
AOP là một kỹ thuật mới đầy triển vọng, hứa hẹn đem lại nhiều lợi ích cho việc
phát triển phần mềm. Việc cấu trúc hóa các ứng dụng với các aspect và thực thi trực
tiếp bằng sử các ngôn ngữ lập trình hướng khía cạnh có khả năng cải thiện chất lượng
các hệ thống phần mềm. Các aspect tạo ra các hệ thống phần mềm lớn và phức tạp có
thể được sản xuất và tổ chức lại đơn giản hơn và cho chất lượng cao hơn. Dưới đây là
một số lợi ích chính của AOP:
Có thể nhận dạng và miêu tả một cách rõ ràng các mối quan tâm cắt ngang
giúp các kiến trúc sư có thể xem xét các hành vi cắt ngang dưới dạng các aspect tại
giai đoạn sớm của vòng đời dự án.
Phân chia trách nhiệm rõ ràng cho các mô-đun riêng lẻ: AOP cho phép tách
các mối quan tâm cắt ngang ra khỏi các mối quan tâm nghiệp vụ chính. Do vậy một
16
mô-đun chỉ nhận trách nhiệm với mối quan tâm nghiệp vụ chính của nó mà không cần
có nghĩa vụ gì với các mối quan tâm cắt ngang nó. Ví dụ như, một mô-đun thực hiện
một giao dịch nghiệp vụ chính và các thông tin thay đổi trong quá trình thực hiện giao
dịch phải được lưu lại thì nó chỉ cần quan tâm đến việc thực hiện giao dịch mà không
cần quan tâm đến thao tác lưu vết giao dịch. Việc lưu vết giao dịch sẽ được thực hiện
trong một aspect bằng AOP. Điều này giúp cho việc phân chia trách nhiệm rõ ràng hơn
và khả năng theo dõi được cải thiện.
Dễ dàng phát triển hệ thống: AOP mô-đun hóa các aspect riêng lẻ do đó khi
hệ thống cần chức năng mới, nhà phát triển chỉ cần tạo ra một aspect thực hiện các yêu
cầu mới đó mà không cần thay đổi các mô-đun nghiệp vụ chính. Khi thêm mô-đun
mới đó vào hệ thống, các aspect hiện có sẽ đan kết với chúng và tạo nên sự phát triển
chặt chẽ. Như vậy hệ thống sẽ đáp ứng nhanh hơn với những yêu cầu mới.
Tái sử dụng mã nguồn: AOP cho phép các nhà phát triển dễ dàng sử dụng lại
mã nguồn của một aspect trong nhiều thành phần và do đó giảm các nỗ lực thể hiện mã
chương trình.
Khả năng mô-đun hóa và đóng gói: AOP làm tăng tính mô-đun hóa và đóng
gói như mã thành phần tốt hơn ngắn gọn và gọn gàng.
Cho phép để lại quyết định thiết kế tương lai: Một thiết kế tốt phải tính đến cả
yêu cầu hiện tại và tương lai, việc xác định yêu cầu tương lai là một công việc khó
khăn. Nếu bỏ sót những yêu cầu tương lai có thể sẽ phải thay đổi hay thực hiện lại
nhiều phần hệ thống. Với AOP, người thiết kế hệ thống có thể để lại các quyết định
thiết kế cho những yêu cầu tương lai nhờ thực hiện theo các aspect riêng biệt.
Rút ngắn thời gian bàn giao sản phẩm: Việc kết nối muộn các giải pháp thiết
kế giúp cho chu trình thiết kế được nhanh hơn. Bên cạnh đó, việc tách biệt rõ ràng các
trách nhiệm của các mô-đun giúp cho người lập trình không gặp nhiều khó khăn trong
việc thực thi các mô-đun, từ đó tăng năng suất làm việc của các nhà lập trình. Việc tái
sử dụng mã nguồn tốt hơn giúp giảm thời gian phát triển hệ thống. Hơn thế nữa, hệ
thống tiến triển dễ dàng hơn giúp cho hệ thống có thể đáp ứng nhanh hơn với các yêu
cầu mới. Tất cả những điều trên giúp cho hệ thống có thể phát triển và triển khai nhanh
hơn.
Giảm thiểu chi phí thực thi: Bằng cách tránh việc sửa đổi nhiều mô-đun khi
phải cài đặt một chức năng cắt ngang, AOP giúp giảm chi phí cài đặt các chức năng
cắt ngang. Với AOP, các lập trình viên có thể tập trung vào các chức năng chính của
của các mô-đun nghiệp vụ và tận dụng được khả năng chuyên môn của họ vào các
công việc chính nên chi phí của các yêu cầu nghiệp vụ chính cũng được giảm xuống.
Như vậy, việc thực thi các chức năng của toàn hệ thống sẽ được giảm thiểu đáng kể.
17
1.3.7. Nhược điểm của phương pháp lập trình hướng khía cạnh
Phương pháp lập trình hướng khía cạnh có nhiều ưu điểm kể trên, tuy nhiên nó
cũng có một số hạn chế sau:
Liệu các aspect có phá vỡ tính đóng gói của các đối tượng? Bình thường các
aspect tuân theo các luật điều khiển truy cập. Bằng cách này hay cách khác, các aspect
có thể phá vỡ tính đóng gói của các đối tượng. Nhưng chúng làm theo cách có thể
kiểm soát được. Các aspect có thể truy cập đến phần riêng tư của các đối tượng mà
chúng tham chiếu đến nhưng không làm tổn hại đến sự đóng gói giữa các đối tượng
của các lớp khác nhau. Ví dụ trong AspectJ, để bỏ qua các luật truy cập ta thêm bổ ngữ
đặc biệt privileged vào trước từ khóa aspect:
privileged aspect EmployeeVerifier {
pointcut verify_experience(Manager staff, int val):
target(staff)&& set(int Manager.experience)&& args(val);
void around(Manager staff, int val):
verify_experience(staff, val) {
if(val<3) {
System.out.println("Manager.experience>=3");
} else{
proceed(staff, val);
}
}
}
Trong ví dụ này, ta có thể truy cập đến thuộc tính experience của lớp Manager
cho dù nó có được bảo vệ bởi từ khóa private hoặc protected hay không.
Giảm hiệu suất thực thi trong trường hợp thực hiện đan kết lúc thực thi hoặc
tốn thời gian nạp chương trình trong trường hợp thực hiện đan kết lúc nạp chương
trình.
Khi chúng ta mắc sai lầm trong việc diễn đạt thực thi cắt ngang có thể gây lỗi
tràn ngập toàn chương trình.
Việc thay đổi các joint point của một chương trình (ví dụ như đổi tên hay di
chuyển các phương thức) mà không được lường trước bởi người viết aspect sẽ gây ra
các lỗi.
Vấn đề bảo mật có thể bị phá vỡ bởi việc sử dụng AOP để cài thêm các đoạn
mã tại các vị trí phù hợp.