Tại sao "đấu"? Nó không phải là "vs". Bạn có thể sử dụng lập trình Aspect hướng kết hợp với lập trình chức năng, nhưng cũng có thể kết hợp với lập trình hướng đối tượng. Nó không phải là "so với", đó là "Lập trình hướng đối tượng với lập trình hướng đối tượng".
Đối với tôi AOP là một loại "lập trình meta". Mọi thứ mà AOP làm cũng có thể được thực hiện mà không cần nó bằng cách thêm mã. AOP chỉ giúp bạn viết mã này.
Wikipedia có một trong những ví dụ tốt nhất cho lập trình meta này. Giả sử bạn có một lớp đồ họa với nhiều phương thức "set ... ()". Sau mỗi phương thức thiết lập, dữ liệu của đồ họa thay đổi, do đó đồ họa thay đổi và do đó đồ họa cần được cập nhật trên màn hình. Giả sử để sơn lại đồ họa, bạn phải gọi "Display.update ()". Cách tiếp cận cổ điển là giải quyết điều này bằng cách thêm nhiều mã hơn . Cuối mỗi phương thức set bạn viết
void set...(...) {
:
:
Display.update();
}
Nếu bạn có 3 phương thức thiết lập, đó không phải là vấn đề. Nếu bạn có 200 (giả thuyết), thật khó để thêm cái này ở mọi nơi. Ngoài ra, bất cứ khi nào bạn thêm một phương thức thiết lập mới, bạn phải chắc chắn không quên thêm phần này vào cuối, nếu không bạn chỉ tạo ra một lỗi.
AOP giải quyết vấn đề này mà không cần thêm hàng tấn mã, thay vào đó bạn thêm một khía cạnh:
after() : set() {
Display.update();
}
Và đó là nó! Thay vì tự viết mã cập nhật, bạn chỉ cần nói với hệ thống rằng sau khi đạt đến điểm đặt set (), nó phải chạy mã này và nó sẽ chạy mã này. Không cần cập nhật 200 phương thức, không cần đảm bảo rằng bạn không quên thêm mã này vào một phương thức thiết lập mới. Ngoài ra, bạn chỉ cần một điểm cắt:
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);
Điều đó nghĩa là gì? Điều đó có nghĩa là nếu một phương thức được đặt tên là "set *" (* có nghĩa là bất kỳ tên nào có thể theo sau khi đặt), bất kể phương thức nào trả về (dấu sao đầu tiên) hoặc tham số nào (dấu hoa thị thứ ba) và đó là phương thức của MyGraphicsClass và đây là phương thức lớp là một phần của gói "com.company. *", sau đó đây là một điểm cắt set (). Và mã đầu tiên của chúng tôi cho biết " sau khi chạy bất kỳ phương thức nào là một điểm cắt đặt, hãy chạy mã sau".
Xem làm thế nào AOP thanh lịch giải quyết vấn đề ở đây? Trên thực tế mọi thứ được mô tả ở đây có thể được thực hiện tại thời gian biên dịch. Bộ tiền xử lý AOP chỉ có thể sửa đổi nguồn của bạn (ví dụ: thêm Display.update () vào cuối mỗi phương thức cắt điểm đặt) trước khi tự biên dịch lớp.
Tuy nhiên, ví dụ này cũng cho thấy một trong những nhược điểm lớn của AOP. AOP thực sự đang làm một cái gì đó mà nhiều lập trình viên coi là " Chống mẫu ". Mẫu chính xác được gọi là " Hành động từ xa ".
Hành động ở xa là một mô hình chống (lỗi phổ biến được nhận biết) trong đó hành vi trong một phần của chương trình thay đổi dữ dội dựa trên khó khăn hoặc không thể xác định các hoạt động trong phần khác của chương trình.
Là một người mới tham gia một dự án, tôi có thể chỉ cần đọc mã của bất kỳ phương thức thiết lập nào và xem nó bị hỏng, vì dường như nó không cập nhật màn hình. Tôi không thấy bằng cách chỉ nhìn vào mã của phương thức set, rằng sau khi nó được thực thi, một số mã khác sẽ "được thực thi" một cách kỳ diệu để cập nhật màn hình. Tôi coi đây là một nhược điểm nghiêm trọng! Bằng cách thay đổi phương thức, các lỗi lạ có thể được đưa ra. Hiểu rõ hơn về dòng mã trong đó một số thứ dường như hoạt động chính xác, nhưng không rõ ràng (như tôi đã nói, chúng chỉ hoạt động một cách kỳ diệu ... bằng cách nào đó), thực sự rất khó.
Cập nhật
Chỉ cần làm rõ rằng: Một số người có thể có ấn tượng Tôi đang nói AOP là một cái gì đó xấu và không nên được sử dụng. Đó không phải là những gì tôi đang nói! AOP thực sự là một tính năng tuyệt vời. Tôi chỉ nói "Sử dụng cẩn thận". AOP sẽ chỉ gây ra sự cố nếu bạn trộn lẫn mã thông thường và AOP cho cùng một khía cạnh . Trong ví dụ trên, chúng ta có khía cạnh cập nhật các giá trị của một đối tượng đồ họa và vẽ đối tượng được cập nhật. Thực tế đó là một khía cạnh duy nhất. Mã hóa một nửa của nó là mã thông thường và nửa còn lại của nó là khía cạnh là những gì thêm vấn đề.
Nếu bạn sử dụng AOP cho một khía cạnh hoàn toàn khác, ví dụ để đăng nhập, bạn sẽ không gặp phải vấn đề chống mẫu. Trong trường hợp đó, một người mới tham gia dự án có thể tự hỏi "Tất cả những thông điệp tường trình này đến từ đâu? Tôi không thấy bất kỳ đầu ra nhật ký nào trong mã", nhưng đó không phải là một vấn đề lớn. Những thay đổi anh ta thực hiện đối với logic chương trình sẽ khó phá vỡ cơ sở nhật ký và những thay đổi được thực hiện đối với cơ sở nhật ký sẽ khó phá vỡ logic chương trình của anh ta - những khía cạnh này hoàn toàn tách biệt. Sử dụng AOP để ghi nhật ký có lợi thế là mã chương trình của bạn hoàn toàn có thể tập trung vào làm bất cứ điều gì cần làm và bạn vẫn có thể ghi nhật ký tinh vi, mà không làm cho mã của bạn bị lộn xộn bởi hàng trăm thông điệp tường trình ở khắp mọi nơi. Ngoài ra khi mã mới được giới thiệu, thông điệp nhật ký kỳ diệu sẽ xuất hiện vào đúng thời điểm với đúng nội dung.
Vì vậy, việc sử dụng AOP tốt trong ví dụ của tôi sẽ là luôn ghi nhật ký nếu có bất kỳ giá trị nào được cập nhật thông qua phương thức đã đặt. Điều này sẽ không tạo ra một mô hình chống và hầu như không phải là nguyên nhân của bất kỳ vấn đề.
Người ta có thể nói, nếu bạn có thể dễ dàng lạm dụng AOP để tạo ra quá nhiều vấn đề, thì đó là một ý tưởng tồi để sử dụng tất cả. Tuy nhiên, công nghệ nào không thể bị lạm dụng? Bạn có thể lạm dụng đóng gói dữ liệu, bạn có thể lạm dụng thừa kế. Khá nhiều công nghệ lập trình hữu ích có thể bị lạm dụng. Hãy xem xét một ngôn ngữ lập trình hạn chế đến mức nó chỉ chứa các tính năng không thể bị lạm dụng; một ngôn ngữ mà các tính năng chỉ có thể được sử dụng như ban đầu chúng được sử dụng. Một ngôn ngữ như vậy sẽ bị hạn chế đến mức không thể tranh cãi nếu nó thậm chí có thể được sử dụng cho lập trình trong thế giới thực.