AOP và AspectJ

1 Giới thiệu 5 1.1 Mục đích và cấu trúc của tài liệu 5 1.2 Các thuật ngữ 5 1.3 Hạn chế của các phương pháp lập trình hiện tại 6 2 Các đặc điểm của AOP 7 2.1 Quản lý các concern hệ thống 8 2.2 Phương pháp luận của AOP 11 2.2.1 Ưu điểm của AOP 12 2.2.2 Những nhược điểm 12 2.3 Một số công cụ hỗ trợ làm việc với AOP 13 3 Giới thiệu AspectJ 13 3.1 Giới thiệu 13 3.2 Một số khái niệm 13 3.2.1 Join point 14 3.2.2 Pointcut 15 3.2.3 Advice 15 3.2.4 Introduction 16 3.2.5 Aspect 17 3.2.6 Static crosscutting 18 3.3 Một số ứng dựng cơ bản của AOP 19 4 Giải quyết bài toán với AOP 20 4.1 Sử dụng AOP trong bước thiết kế 20 4.2 Sử dụng AOP trong bước thi công 21 4.3 Sử dụng AOP trong bước kiếm tra 21 4.4 Sử dụng AOP trong giai đoạn bảo trì 22 5 Triển khai một số pattern trên AspectJ 22 5.1 Các mẫu thiết kế cho việc tạo đối tượng 23 5.1.1 Singleton pattern 23 5.1.2 Prototype pattern 25 5.1.3 Abstract Factory pattern 27 5.1.4 Factory Method pattern 29 5.1.5 Builder pattern 30 5.2 Các mẫu thiết kế cho cấu trúc của đối tượng 32 5.2.1 Composite pattern 32 5.2.2 Flyweight pattern 35 5.2.3 Bridge Pattern 36 5.2.4 Decorator pattern 38 5.2.5 Adapter pattern 39 5.2.6 Proxy Pattern 40 5.3 Các mẫu thiết kế cho hành vi của đối tượng 42 5.3.1 Observer pattern 42 5.3.2 Command Pattern 46 5.3.3 Iterator pattern 50 5.3.4 Mediator pattern 51 5.3.5 Chain of Responsibility Pattern 53 5.3.6 Memento Pattern 56 5.3.7 Visitor Pattern 58 5.3.8 Strategy pattern 61 5.3.9 State Pattern 63 6 Kết luận 64 7 Tài liệu tham khảo 66

doc66 trang | Chia sẻ: lvcdongnoi | Lượt xem: 3220 | Lượt tải: 3download
Bạn đang xem trước 20 trang tài liệu AOP và AspectJ, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Connection connection) throws SQLException : connectionOperation (connection) { System.out.println("Operation " + thisJoinPoint + " on " + connection+ " started at " + System.currentTimeMillis()); proceed(connection); System.out.println("Operation " + thisJoinPoint + " on " + connection + " completed at " + System.currentTimeMillis()); } Nếu trong around advice muốn thực hiện thao tác tại join point, phải sử dụng từ khoá proceed(). Introduction Introduction là một lệnh chỉ ra sự thay đổi đến một class, interface, aspect. Nó tạo ra sự thay đổi tĩnh đến các module mà không trực tiếp ảnh hưởng đến các hành vi của module đó. Ví dụ có thể thêm một phương thức hoặc một trường vào lớp nào đó hoặc sửa đổi cấu trúc thừa kế của một đối tượng. Ví dụ khai báo sau sẽ sửa đổi cấu trúc thừa kế của đối tượng Account. declare parents: Account implements BankingEntity; Introduction là khái niệm sinh ra để can thiệp vào các cấu trúc tĩnh, trong AOP nó được dùng để xử lý các quan hệ đan xen tĩnh (static crosscutting). Chúng ta sẽ đề cập đến vấn đề này trong phần static crosscutting. Aspect Aspect là phần tử tập trung của AspectJ, giống như class trong Java. Aspect chứa mã thể hiện các luật đan kết cho concern. Join point, pointcut, advice, introduction được kết hợp trong aspect. Aspect được khai báo theo mẫu sau [access specification] aspect [extends class-or-aspect-name] [implements interface-list] [(Pointcut)] { ... aspect body } Ví dụ sau khai báo một aspect: public aspect ExampleAspect { before() : execution(void Account.credit(float)) { System.out.println("About to perform credit operation"); } declare parents: Account implements BankingEntity; declare warning : call(void Persistence.save(Object)) : "Consider using Persistence.saveOptimized()"; } Một số tính chất của khái niệm aspect tương tự khái niệm class Aspect có thể chứa các thuộc tính và phương thức Aspect chứa các thuộc tính truy cập: private, public, protected .. Aspect có thể khai báo như một aspect trừu tượng: public abstract aspect AbstractLogging { public abstract pointcut logPoints(); public abstract Logger getLogger(); before() : logPoints() { getLogger().log(Level.INFO, "Before: " + thisJoinPoint); } } Aspect có thể thừa kế class, abstract aspect và thi công các interface public aspect BankLogging extends AbstractLogging { public pointcut logPoints() : call(* banking..*(..)); public Logger getLogger() { return Logger.getLogger("banking"); } } Aspect có thể nhúng trong class và interface như một aspect nằm trong Ngoài các tính chất tương tự class như trên, aspect cũng có một số đặc điểm khác so với class như sau: Aspect không thể khởi tạo trực tiếp Aspect không thể thừa kế từ một aspect khác (không phải trừu tượng) Aspect có thể được đánh dấu như quyền Static crosscutting Trong AOP chúng ta thường xuyên can thiệp vào các quan hệ đan xen động sử dụng advice, và cũng cần thiết các hành động can thiệp vào các cấu trúc tĩnh. Trong khi các concern đan xen động sẽ sửa đổi sự thực hiện các thủ tục của chương trình thì sự đan xen tĩnh sẽ sửa đổi các cấu trúc như class, interface, các aspect khác và các hành vi tại điểm dịch chương trình. Giới thiệu thành viên Aspect thường xuyên giới thiệu các thành viên hoặc các phương thức vào trong một lớp aspect . AspectJ cung cấp một có chế được gọi là introduction để giới thiệu các thành viên vào trong các class hoặc interface. Đoạn mã dưới đây mô tả cách giới thiệu 2 thành viên là thuộc tính minimumBalance và phương thức getAvailable() vào lớp Account. Các thành viên được giới thiệu vào một lớp cũng có thể được chỉ ra quyền truy nhập như khai báo các thành viên của một lớp. Ví dụ từ khoá private chỉ ra thành viên chỉ được truy cập từ aspect giới thiệu nó. public aspect MinimumBalanceRuleAspect { private float Account._minimumBalance; public float Account.getAvailableBalance() { return getBalance() - _minimumBalance; } after(Account account) : execution(SavingsAccount.new(..)) && this(account) { account._minimumBalance = 25; } before(Account account, float amount)throws InsufficientBalanceException : execution(* Account.debit())&& this(account) && args(amount) { if (account.getAvailableBalance() < amount) { throw new InsufficientBalanceException( "Insufficient available balance"); } } Sửa đổi cấu trúc thừa kế Khi thực thi các quan hệ đan xen thường xuyên cần tác động đến tập các class hoặc interface mà chúng có chung một kiểu cơ sở. AspectJ có thể sửa đổi cây thừa kế của một lớp đã tồn tại để khai báo các lớp cha hoặc các interface của lớp đó miễn là không ảnh hưởng đến qui luật thừa kế của Java. Mẫu khai báo như sau: declare parents : [ChildTypePattern] implements [InterfaceList]; declare parents : [ChildTypePattern] extends [Class or InterfaceList]; Ví dụ : Aspect khai báo tất cả các class và interface trong gói entities thực thi Identifiable interface. aspect AccountTrackingAspect { declare parents : banking..entities.* implements Identifiable; ... tracking advices } Một số ứng dựng cơ bản của AOP Dưới đây là một số ứng dụng điển hình sử dụng các ưu điểm của AOP trong việc thiết kế và triển khai Các kỹ thuật điều khiển, giám sát (monitor): Các kỹ thuật điều khiển, giám sát như logging, tracing, profiling là những kỹ thuật chung để hiểu được các hành vi xảy ra trong hệ thống. Ví dụ trong hệ thống nhà băng người quản trị muốn theo dõi thông tin mỗi giao dịch trong hệ thống như tên tài khoản, thời gian giao dịch. Vì các chức năng này xuyên suốt qua các module của ứng dụng nên khi triển khai các kỹ thuật này với AOP là một cách tiếp cận tốt nhất có thể Tăng cường chính sách (policy enforcement): Là một cơ chế bảo đảm các thành phần trong hệ thống phải theo các quy tắc lập trình thực tế, tuân theo một số luật cụ thể. Ví dụ bạn không thể gọi đến thư viên xử lý giao diện AWT trong mã của EJB được. Tối ưu hóa (resource pooling và caching): Khái niệm resource pooling và caching chúng ta thường xuyên phải sử dụng trong các tình huống muốn tối ưu hóa ứng dụng. Giải quyết bài toán với AOP Trong phần này chúng ta sẽ xem xét một số bài toán và một số giải pháp thực tiễn để giúp một ứng dụng triển khai được trên AOP. Việc áp dụng một công nghệ mới để giải quyết bài toán không bao giờ dễ dàng, đặc biệt khi bạn còn chưa nhìn thấy một hệ thống nào triển khai thành công với công nghệ mới này. Chúng ta sẽ tìm hiểu cách sử dụng mô hình hướng aspect như thế nào để giải quyết bài toán và các giải pháp về thiết kế. Một khi thực sự chắc chắn muốn sử dụng AOP trong hệ thống phần mềm nào đó, ta cần xác định tính thích hợp cho mỗi vấn đề khác nhau. Cần phải xem xét khả năng tối thiểu các rủi ro của hệ thống. Chẳng hạn chúng ta có thể áp dụng AOP cho các module con, sau khi chứng minh được khả năng của AOP, chúng ta sẽ tiếp tục triển khai trên các module tiếp theo. Mỗi pha trong quá trình phát triển phần mềm: thiết kế, thi công, test và bảo trì đều nhấn mạnh tới một số hành động. Sử dụng AOP trong bước thiết kế Nếu sử dụng AOP trong bước thiết kế chúng ta sẽ có được nhiều sự thuận lợi mà AOP đem lại. Từ quan điểm về kiến trúc, sự thuận lợi chính là giúp chúng ta vượt qua sự bế tắc của các kiến trúc hiện tại. Sau đây là một số bước điển hình sử dụng AOP trong pha thiết kế Nhận biết các concern đan xen: Bước này là một phần trong việc ánh xạ các yêu cầu người dùng tới các module. Một quy tắc là xem xét các concern được mô tả với các tính tù hoặc trạng từ bắt đầu với từ “mọi”, ví dụ như mọi ngày, mọi nơi…Nhận biết các concern này ban đầu sẽ giúp chúng ta tránh khỏi việc module hoá các concern đan xen theo phương pháp truyền thống. Thiết kế các concern lõi trước: Áp dụng các quy tắc và phương pháp truyền thống để thiết kế các concern lõi. Công việc này càng làm tốt thì việc áp dụng các concern đan xen sau này càng dễ. Thiết kế các concern đan xen: Xác định các concern đan xen cần thiết, dễ thấy. Lên một bộ khung cho các concern bạn cần và cũng có thể cả các concern bạn chưa cần ngay lập tức. Sử dụng AOP trong bước thi công Khi sử dụng AOP trong bước thi công bạn nên nhấn mạnh vào trên một vài thực tiễn có tính chất chung. Cũng như cần theo một số chỉ dẫn để việc thi công các concern lõi và concern đan xen dẽ nhất có thể. Cũng có một số phương pháp refactoring theo mô hình AOP bạn có thể sử dụng Thực thi các concern lõi Viết các concern lõi theo mô hình refactoring tốt nhất. Sử dụng cách đặt tên nhất quán xuyên suốt ứng dụng Tách biệt các concern đan xen từ các module trong bước đầu tiên. Xem xét bất kỳ sự rải rác và chồng chéo mã chương trình Thực thi các concern đan xen Xác định các join point: Bước này cần xác định các vị trí trong mã chương trình cần cho các quan hệ đan xen. Tiếp theo cần quyết định cách tốt nhất để thể hiện các pointcut mà chúng sẽ chọn các join point Lựa chọn các kỹ thuật sử dụng ở lớp dưới Thiết kế các aspect Thực hiện refactoring các aspect Sử dụng AOP trong bước kiếm tra AspectJ có thể trợ giúp nhiều nhiệm vụ trong bước kiếm tra, Sau đây là một kịch bản điển hình mà chúng ta có thể bắt đầu thực hiện với AspectJ Tạo các test case: Do AspectJ có khả năng sửa đổi các hành vi mà không cần sự thay đổi thực sự nên AspectJ có thể trợ giúp để viết các chương trình kiểm tra. Thực hiện kiểm tra hiệu năng hệ thống: Rất nhiều vấn đề chỉ được phát hiện ra vào thời điểm triển khai hệ thống.AspectJ có thể bất chế độ theo dõi hiệu năng các aspect, do đó chúng ta có thể xác định được kết quả gần với các hệ thống thực, và chúng ta có thể quyết định sử dụng aspect hay không trên hệ thống triển khai để tránh tràn bộ nhớ. Báo cáo lỗi: Trong quá trình kiểm tra, khi chúng ta phát hiện ra các lỗi thì có thể sử dụng aspect để chỉ ra các ngữ cảnh trong ứng dụng chứ không phải chỉ là ngăn xếp của ngoại lệ được ném ra. Sử dụng AOP trong giai đoạn bảo trì Giai đoạn bảo trì hệ thống bao gồm hai thao tác chính sau Thêm mới tính năng cho các yêu cầu mới Sửa các lỗi được tìm thấy AspectJ có thể điều khiển 2 bước sau trong giai đoạn bảo trì Tạo một bức tường an toàn: Thêm các tính năng mới mà không làm đổ vỡ hệ thống, Các chế độ tăng cường của aspect bảo đảm rằng các tính năng mới không ảnh hưởng đến hệ thống cũng như tạo ra các lỗi mới Thực thi các tính năng mới: AspectJ có thể thêm các quan hệ đan xen mới mà không thay đổi trực tiếp trên mã nguồn gốc Triển khai một số pattern trên AspectJ Mẫu thiết kế (design pattern) được sử dụng rất nhiều khi phát triển một phần mềm, nó giúp người phát triển giải quyết các vấn đề như điều khiển đối tượng, tái sử dụng mã, tăng hiệu năng chương trình. “Design Patterns: Elements of Reusable Object-Oriented Software” được biên soạn bởi Erich Gamma, Richard Helm, Ralph Johnson, và John Vlissides là một cuốn sách về design pattern đã được công nhận chính thức như một tài liệu thực tiễn cho mô hình lập trình hướng đối tượng (OOP). Các mẫu thiết kế trong quyển sách này được chia thành 3 loại, bao gồm: các mẫu thiết kế về cấu trúc đối tượng, hành vi đối tượng, và tạo lập đối tượng. Các mẫu thiết kế được thực thi dựa trên cơ chế của các ngôn ngữ lập trình hướng đối tượng đang có. Với mô hình lập trình hướng aspect, các mẫu thiết kế được xây dựng với một số đặc điểm mới nhằm tận dụng được những ưu điểm của phương pháp mới này. Các mẫu thiết kế cho việc tạo đối tượng Singleton pattern Giới thiệu Singleton pattern là một mẫu thiết kế để đảm bảo trong một phiên làm việc của ứng dụng chỉ có duy nhất một thể hiện ( instance) của đối tượng vào lúc chạy. Mẫu thiết kế này thường được sử dụng để quản lý thông tin của một phiên làm việc của một ứng dụng. Đối tượng không được khởi tạo trực tiếp trong chương trình (các hàm khởi tạo của đối tượng được khai báo với từ khoá private) mà sẽ truy xuất qua một hàm static để trả về thể hiện duy nhất của đối tượng. public abstract aspect SingletonPattern issingleton( ) { private Hashtable singletons = new Hashtable( ); public interface Singleton { } public interface NonSingleton { } // Pointcut định nghĩa các đối lớp cto define specify an interest in all creations // of all Classes that extend Singleton pointcut selectSingletons( ) : call((Singleton +).new (..)); // Pointcut bảo đảm bất kỳ lớp nào trong cây thừa kế được đánh dấu //là Non Singletons thì không được gộp trong logic của Singleton pointcut excludeNonSingletons( ) : !call((NonSingleton +).new (..)); Object around() : selectSingletons() && excludeNonSingletons( ) { Class singleton = thisJoinPoint.getSignature().getDeclaringType( ); synchronized(singletons) { if (singletons.get(singleton) == null) { singletons.put(singleton, proceed( )); } } return (Object) singletons.get(singleton); } } Aspect trừu tượng Singleton định nghĩa 2 vai trò: Singleton và NonSingleton. Các vai trò này được thi công bởi interface nên các aspect trừu tượng có thể làm việc với singleton mà không cần lo lắng về cách thi công chi tiết. Hình 8: Cấu trúc của aspect trừu tượng với interface và các hàm được định nghĩa để hỗ trợ Singleton pattern Sử dụng Sau đây là ví dụ chỉ ra aspect SingletonPattern được sử dụng trong ứng dụng: Hình 9:Một ứng dụng trước và sau khi được tác động bởi Singleton pattern public aspect PrinterSingleton extends SingletonPattern { declare parents: Printer implements Singleton; declare parents: SpecializedPrinter implements NonSingleton; } Hình sau minh hoạ hoạt động của ứng dụng khi gọi hàm in 2 lần, lần đầu khi instance của Printer chưa có, nó sẽ được khởi tạo lần đầu. Lần tiếp theo khi instance đã tồn tại, hàm in sẽ lấy tham chiếu đến instance đã được khởi tạo ở bước đầu tiên. Hình 10: Các bước thực hiện của mẫu thiết kế Singleton trong ứng dụng Prototype pattern Giới thiệu Prototype pattern được sử dụng hỗ trợ sao chép một đối tượng dựa trên đối tượng gốc. public abstract aspect PrototypePattern { protected interface Prototype { } public Object Prototype.clone() throws CloneNotSupportedException { return super.clone( ); } public Object cloneObject(Prototype object) { try { return object.clone( ); } catch (CloneNotSupportedException ex) { return createCloneFor(object); } } protected Object createCloneFor(Prototype object) { return null; } } Aspect PrototypePattern định nghĩa Prototype interface mà nó có thể ứng dụng cho bất cứ lớp nào trong ứng dụng cụ thể mà nó được là một nguyên mẫu. Những lớp này sẽ thừa kế với hàm clone() để hỗ trợ việc sao chép đối tượng. Hình 11: Cấu trúc của PrototypePattern aspect Sử dụng public aspect GraphicPrototypes extends PrototypePattern { declare parents : Graphic implements Prototype; declare parents : MusicalNote implements Prototype; declare parents : Staff implements Prototype; protected Object createCloneFor(Prototype object) { if (object instanceof MusicalNote) { return new MusicalNote(((MusicalNote) object).getX( ), ((MusicalNote) object).getY( )); } else if (object instanceof Staff) { return new Staff(((Staff) object).getX(), ((Staff) object).getY( )); } else { return null; } } } Hình 12:Một ứng dụng trước và sau khi được tác động bởi Prototype pattern Hình 13: Sử dụng Prototype pattern trong ứng dụng Abstract Factory pattern Mẫu thiết kế này được sử dụng khi thao tác trên nhóm các lớp có quan hệ với nhau trong khi nó che giấu sự thực thi các lớp này đối với client. Theo mô hình lập trình OOP thì factory pattern cung cấp các lợi ích sau: Client không cần phải quan tâm đến việc chọn một concrete class để tạo object mà mình muốn. Client không cần phải liên hệ trực tiếp với lớp thực thi cụ thể (concrete class) mà thông qua interface hoặc abstract class. Client không cần phải biết quá trình tạo object như thế nào Mô hình của pattern được mô tả trong hình sau. Hình 14: Lược đồ UML của AbstractFactory Pattern Tạo một factory sử dụng aspect không mang ý nghĩa lắm bởi vì factory chứa các phương thức cụ thể đến các đối tượng có thể được tạo. Ưu điểm duy nhất của AOP đối với pattern này là khả năng loại bỏ sự nương tựa vào một lớp abstract cơ sở cho các abstract factory và thay thế chúng với một interface đơn giản. Điều này có nghĩa là các factory cụ thể có thể thừa kế từ lớp thích hợp khác hơn là sử dụng một quan hệ thừa kế được phép để hỗ trợ mẫu thiết kế. Đoạn mã AspectJ sau đây chỉ ra cách thực hiện pattern này. public interface ComputerFactory { public Computer createPentiumProcessorComputer( ); public Computer createComputerWithHardDisk(HardDisk hardDisk); } public aspect DefaultComputerFactoryImplementation { public Computer ComputerFactory.createPentiumProcessorComputer( ) { Processor processor = new Processor("Pentium 4 : 9089085043"); Motherboard motherboard = new Motherboard("019283", processor); HardDisk hardDisk = new HardDisk("738947"); FloppyDisk floppyDisk = new FloppyDisk("93746"); Computer computer = new Computer("12345", motherboard, hardDisk, floppyDisk); return computer; } public Computer ComputerFactory.createComputerWithHardDisk(HardDisk hardDisk) { Processor processor = new Processor("Pentium Standard : 123478"); Motherboard motherboard = new Motherboard("434244", processor); FloppyDisk floppyDisk = new FloppyDisk("432434"); Computer computer = new Computer("56789", motherboard, hardDisk, floppyDisk); return computer; } } Factory Method pattern Factory method pattern tương tự abstract factory khi nó cung cấp cơ chế mà sự thi công cụ thể của các đối tượng được tách riêng từ các client của factory. Một phương thức trừu tượng (Factory method ) cung cấp một phương thức để khởi tạo các instance khác nhau của một interface. Hình 15: Lược đồ UML của factory method pattern Đoạn mã AspectJ sau mô tả cách thực hiện pattern này: public interface ComputerCreator { public Computer createComputer(String serial); } public aspect DefaultComputerCreatorImplementation { public void ComputerCreator.createComputerAndPrintInventory(String serial) { System.out.println("Inventory of computerparts:"); System.out.println(this.createComputer(serial).toString( )); } } Thường thì ComputerCreator trong pattern này là một lớp trừu tượng (abstract class). Tuy nhiên các kỹ thuật về static crosscutting cung cấp mềm dẻo hơn khi sử dụng pattern này bằng cách loại bỏ lớp trừu tượng cơ sở. Builder pattern Giới thiệu Builder pattern được sử dụng để tạo một đối tượng cần đến một tập các bước thực hiện phức tạp. Các bước này được thi công như những phương thức của lớp builder, sau khi hoàn tất mỗi bước builder có thể được gọi để tạo đối tượng. Builder pattern có các lợi ích sau: Tách quá trình tạo một object ra bên ngoài bản thân class của object đó. Tạo khả năng mềm dẻo trong việc đưa ra các implementation khác nhau cho qúa trình tạo object Để thực hiện Builder pattern trong AspectJ, cần tạo một aspect mà nó thêm vào lớp cao nhất của lớp builder. Ví dụ: public interface TextPhraseBuilder { public void buildHeader(String title); public void buildBody(String content); public void buildFooter(String closingContent); public String getResult( ); } public aspect TextPhraseBuilderDefaultImplementation { public StringBuffer TextPhraseBuilder.result = new StringBuffer( ); public String TextPhraseBuilder.getResult( ) { return result.toString( ); } /** * Declares a compiler error that gets reported if other classes * (except Builders or this aspect) try to access the result variable. */ declare error : ( set(public StringBuffer TextPhraseBuilder +.result) || get(public StringBuffer TextPhraseBuilder +.result)) && !(within(TextPhraseBuilder +) || within(TextPhraseBuilderDefaultImplementation)) : "variable result is aspect protected. use getResult( ) to access it"; } Aspect TextPhraseBuilderDefaultImplementation cung cấp một phương thức thi công mặc định cho phương thức (). Sự tiện lợi này .. Phương thức getResult() cung cấp sự truy cập đến trường result mà nó đã được thêm vào interface và các lớp thực thi để cung cấp một nơi lưu giữ các kết quả của builder. Trường result có thể nên khai báo quyền truy xuất là protected để nó chỉ được sử dụng trong bản thân lớp chứa nó và các lớp con của nó. Các mẫu thiết kế cho cấu trúc của đối tượng Composite pattern Composite pattern cung cấp khả năng nhóm các đối tượng cùng nhau trong một tập hợp và tương tác với nhóm tương tự như cách thao tác với một đối tượng thành viên độc lập của nhóm. Composite pattern aspect định nghĩa giao diện Composite và Leaf để áp dụng vào các ứng dụng cần sử dụng vai trò của 2 giao diện này. Aspect sử dụng Visitor pattern để duyệt đệ quy và làm việc với các thành phần của composite. Hình 16: Cấu trúc của CompositePattern aspect public abstract aspect CompositePattern { public interface Component { } protected interface Composite extends Component { } protected interface Leaf extends Component { } private WeakHashMap perComponentChildren = new WeakHashMap( ); private Vector getChildren(Component s) { Vector children = (Vector) perComponentChildren.get(s); if (children == null) { children = new Vector( ); perComponentChildren.put(s, children); } return children; } public void addChild(Composite composite, Component component) { getChildren(composite).add(component); } public void removeChild(Composite composite, Component component) { getChildren(composite).remove(component); } public Enumeration getAllChildren(Component c) { return getChildren(c).elements( ); } public interface Visitor { public void doOperation(Component c); } public void recurseOperation(Component c, Visitor v) { for (Enumeration enum = getAllChildren(c); enum.hasMoreElements( );) { Component child = (Component) enum.nextElement( ); v.doOperation(child); } } public interface FunctionVisitor { public Object doFunction(Component c); } public Enumeration recurseFunction(Component c, FunctionVisitor fv) { Vector results = new Vector( ); for (Enumeration enum = getAllChildren(c); enum.hasMoreElements( );) { Component child = (Component) enum.nextElement( ); results.add(fv.doFunction(child)); } return results.elements( ); } } Ví dụ sử dụng: public aspect GraphicsComposite extends CompositePattern { declare parents : Window implements Composite; declare parents : Line implements Leaf; declare parents : Rectangle implements Leaf; public void Component.draw(PrintStream s) { s.println("Drawing: " + this); } public void Composite.draw(final PrintStream s) { s.println("Composite: " + this); GraphicsComposite.aspectOf( ).recurseOperation(this, new Visitor( ) { public void doOperation(Component c) { c.draw(s); } }); } public void Leaf.draw(PrintStream s) { s.println("Drawing Leaf: " + this); } } Hình 17: Mô hình các đối tượng trước khi áp dụng Composite pattern Hình 18: Mô hình các đối tượng sau khi áp dụng Composite pattern Hình 19: Hoạt động của composite pattern trong ứng dụng Flyweight pattern Mẫu thiết kế này hỗ trợ giảm sự chi tiết của các đối tượng trong hệ thống bằng cách chia sẻ các đối tượng. Hình 20: Cấu trúc của FlyweightPattern aspect public abstract aspect FlyweightPattern { private Hashtable flyweightPool = new Hashtable( ); public interface Flyweight { }; protected abstract pointcut flyweightCreation(Object key); Object around(Object key) : flyweightCreation(key) && !within(com.oreilly.aspectjcookbook.oopatterns.FlyweightPattern+) { return this.checkFlyweight(key); } public synchronized Flyweight checkFlyweight(Object key) { if (flyweightPool.containsKey(key)) { return (Flyweight) flyweightPool.get(key); } else { Flyweight flyweight = createNewFlyweight(key); flyweightPool.put(key, flyweight); return flyweight; } } protected abstract Flyweight createNewFlyweight(Object key); } Ví dụ sử dụng: public aspect PrintableCharacterFlyweight extends FlyweightPattern { declare parents : PrintableCharacter implements Flyweight; protected pointcut flyweightCreation(Object key) : call(public com.oreilly.aspectjcookbook.PrintableCharacter. new(Character)) && args(key); protected Flyweight createNewFlyweight(Object key) { return new PrintableCharacter((Character) key); } } Bridge Pattern Mẫu thiết kế này tách riêng một lớp từ các tính chất của một thi công cụ thể mà các lớp thực thi khác có thể áp dụng mà không cần tác động vào các lớp client. public class Window { public void drawText(String text) { } public void drawRect( ) { } } public aspect XWindowBridge perthis(captureAllBridgedCalls( )) { private XWindow imp = new XWindow( ); public pointcut captureDrawText(String text) : execution(public void Window.drawText(String)) && args(text); public pointcut captureDrawRect( ) : execution(public void Window. drawRect( )); public pointcut captureAllBridgedCalls( ) : captureDrawText(String) || captureDrawRect( ); void around(String text) : captureDrawText(text) { imp.drawText(text); } void around( ) : captureDrawRect( ) { imp.drawLine( ); imp.drawLine( ); imp.drawLine( ); imp.drawLine( ); } } Hình 21:Cấu trúc của XWindowBridge aspect Ví dụ sử dụng: Hình 22: Sử dụng các hành vi của lớp Window trong ứng dụng Decorator pattern Mẫu thiết kế này thừa các hành vi của một lớp trong khi duy trì public interface mà không cần hiểu về lớp hoặc để tâm đến sự mở rộng. public abstract aspect DecoratorPattern { public interface DecoratedComponent { }; private boolean DecoratedComponent.decorated = false; public void DecoratedComponent.setDecorated(boolean decorated) { this.decorated = decorated; } public void DecoratedComponent.isDecorated(boolean decorated) { return this.decorated ; } } Hình 23: Cấu trúc của DecoratorPattern aspect Ví dụ sử dụng: public aspect TextDisplayDecorator extends DecoratorPattern { declare parents : TextDisplay implements DecoratedComponent; public pointcut selectDecorators(Object object) : call(public void TextDisplay.display(String)) && target(object); before(Object object) : selectDecorators(object) && if(((DecoratedComponent)object).getDecorated) { System.out.print(""); } after(Object object) : selectDecorators(object) && if(((DecoratedComponent)object).getDecorated) { System.out.print(""); } } Hình 24:Lớp TextDisplay trước và sau khi áp dụng DecoratorPattern Adapter pattern Mẫu thiết kế này giúp thay đối một thông điệp được gửi từ một đối tượng thành một thông điệp được chấp nhận bởi đối tượng đích. Sự thích ứng thông điệp này phải gắn với hai đối tượng. public aspect PrinterScreenAdapter { declare parents : Screen implements Printer; public void Screen.print(String s) { outputToScreen(s); } } Hình 25: Áp dụng Adapter pattern Proxy Pattern Proxy Pattern cho phép người phát triển cung cấp một đối tượng đại diện cho một đối tượng khác trong trường hợp đối tượng cần được đại diện hoặc được điều khiển. Hình 26: Cấu trúc của ProxyPattern aspect public abstract aspect ProxyPattern { protected interface Subject { } protected abstract pointcut requestTriggered( ); private pointcut accessByCaller(Object caller) : requestTriggered( ) && this(caller); private pointcut accessByUnknown( ) : requestTriggered( ) && !accessByCaller(Object); Object around(Object caller, Subject subject) : accessByCaller(caller) && target(subject) { if (reject(caller, subject, thisJoinPoint)) { return rejectRequest(caller, subject, thisJoinPoint); } else if (delegate(caller, subject, thisJoinPoint)) { return delegateRequest(caller, subject, thisJoinPoint); } return proceed(caller, subject); } Object around(Subject subject) : accessByUnknown( ) && target(subject) { // Without a caller then reject does not really make sense // as there is no way of deciding to reject or not if (delegate(null, subject, thisJoinPoint)) { return delegateRequest(null, subject, thisJoinPoint); } return proceed(subject); } protected abstract boolean reject( Object caller, Subject subject, JoinPoint joinPoint); protected abstract boolean delegate( Object caller, Subject subject, JoinPoint joinPoint); protected abstract Object rejectRequest( Object caller, Subject subject, JoinPoint joinPoint); protected abstract Object delegateRequest( Object caller, Subject subject, JoinPoint joinPoint); } Ví dụ sử dụng: public aspect DelegationProxy extends ProxyPattern { declare parents : RealSubject implements Subject; protected pointcut requestTriggered( ) : call(* RealSubject.write(..)); protected boolean reject( Object caller, Subject subject, JoinPoint joinPoint) { return false; } protected boolean delegate( Object caller, Subject subject, JoinPoint joinPoint) { return true; } protected Object rejectRequest( Object caller, Subject subject, JoinPoint joinPoint) { return null; } protected Object delegateRequest( Object caller, Subject subject, JoinPoint joinPoint) { Object[] args = joinPoint.getArgs( ); if (args != null) { AnotherRealSubject.write((String) args[0]); } else { AnotherRealSubject.write(""); } return null; } } Các mẫu thiết kế cho hành vi của đối tượng Observer pattern Giới thiệu Mẫu thiết kế này dùng để định nghĩa mối quan hệ phụ thuộc 1:n giữa các đối tượng, khi một đối tượng thay đổi trạng thái thì các đối tượng phụ thuộc nó được thông báo và cập nhật một cách tự động. Ví dụ chúng ta muốn duy trì quan hệ phụ thuộc giữa Employe và Department, khi Employe thay đổi trạng thái thì Department phải được cập nhật và thông báo. Chúng ta xây dựng aspect cho mẫu thiết kế này như sau: Định nghĩa 2 vai trò: Subject và Observer. Khi chúng ta thừa kế aspect, chúng ta sẽ sử dụng các subaspect để tác động những quyền đó vào Employe và Department. Nó cũng duy trì tập các ánh xạ giữa các Subject và các Observer. Mỗi Subject có một hay nhiều các Observer. Các aspect thừa kế có thể sử dụng addObserver() hoặc removeObserver() để tác động vào danh sách ánh xạ Hình 27: Cấu trúc của ObserverPattern aspect public abstract aspect ObserverPattern { protected interface Subject { public void addObserver(Observer observer); public void removeObserver(Observer observer); } protected interface Observer { public void notifyOfChange(Subject subject); } private List Subject.observers = new LinkedList( ); public void Subject.addObserver(Observer observer) { this.observers.add(observer); } public void Subject.removeObserver(Observer observer) { this.observers.remove(observer); } private synchronized void Subject.notifyObservers( ) { Iterator iter = this.observers.iterator( ); while (iter.hasNext( )) { ((Observer)iter.next( )).notifyOfChange(this); } } protected abstract pointcut subjectChange(Subject s); after(Subject subject) : subjectChange(subject) { subject.notifyObservers( ); } } Sử dụng Observer pattern Để sử dụng được mẫu thiết kế này đầu tiên chúng ta cần phải xác định được yêu cầu bài toán, cụ thể là cần trả lời những câu hỏi sau. Đối tượng nào là Subject và đối tượng nào là Observer ? Cái gì cấu tạo thành sự thay đối trong Subject Cái gì cấu tạo thành sự cập nhật trong Observer Khi nào Observer bắt đầu theo dõi Subject và khi nào dừng theo dõi Ví dụ sau minh hoạ cách sử dụng Observer pattern Hình 28: Cấu trúc lớp trước khi áp dụng ObserverPattern Hình 29:Cấu trúc lớp sau khi áp dụng ObserverPattern public aspect ConcreteClassAObserver extends ObserverPattern { declare parents : ConcreteClassB implements Subject; declare parents : ConcreteClassA implements Observer; protected pointcut subjectChange(Subject s) : call(* ConcreteClassB.set*(..)) && target(s); public void ConcreteClassA.notifyOfChange(Subject subject) { this.doSomething( "ConcreteClassA was notified of a change on " + subject); } } Hình 30:Sử dụng ObserverPattern trong ứng dụng Command Pattern Command pattern hỗ trợ sự đóng gói các yêu cầu như các đối tượng trong phạm vi những quyền của chúng. Các đơn hoặc đa thao tác có thể được kết hợp trong một yêu cầu hoặc một giao tác phụ thuộc vào tuỳ từng mục đích của chúng. Khi đối tượng yêu cầu được đã được xây dựng, nó có thể được quản lý như các thực thể tách rời từ đối tượng ban đầu. Command pattern được sử dụng trong các trường hợp sau Hỗ trợ undo, logging, hoặc transaction Hàng đợi và thực hiện các lệnh tại các thời điểm khác nhau Tách biệt giữa nguồn của yêu cầu với đối tượng thực hiện yêu cầu Hình 31: Cấu trúc của CommandPattern và các hàm hỗ trợ pattern public abstract aspect CommandPattern { public interface Command { public void executeCommand(CommandReceiver receiver); public boolean isExecutable( ); } public interface CommandInvoker { } public interface CommandReceiver { } private WeakHashMap mappingInvokerToCommand = new WeakHashMap( ); public Object setCommand(CommandInvoker invoker, Command command) { return mappingInvokerToCommand.put(invoker, command); } public Object removeCommand(CommandInvoker invoker) { return setCommand(invoker, null); } public Command getCommand(CommandInvoker invoker) { return (Command) mappingInvokerToCommand.get(invoker); } private WeakHashMap mappingCommandToReceiver = new WeakHashMap( ); public Object setReceiver(Command command, CommandReceiver receiver) { return mappingCommandToReceiver.put(command, receiver); } public CommandReceiver getReceiver(Command command) { return (CommandReceiver) mappingCommandToReceiver.get(command); } protected abstract pointcut commandTrigger(CommandInvoker invoker); after(CommandInvoker invoker) : commandTrigger(invoker) { Command command = getCommand(invoker); if (command != null) { CommandReceiver receiver = getReceiver(command); command.executeCommand(receiver); } else { // Do nothing: This Invoker has no associated command } } protected pointcut setCommandTrigger(CommandInvoker invoker, Command command); after(CommandInvoker invoker, Command command) : setCommandTrigger( invoker, command) { if (invoker != null) setCommand(invoker, command); } protected pointcut removeCommandTrigger(CommandInvoker invoker); after(CommandInvoker invoker) : removeCommandTrigger(invoker) { if (invoker != null) removeCommand(invoker); } public boolean Command.isExecutable( ) { return true; } } Ví dụ sử dụng command pattern Hình 32: Trước khi áp dụng CommandPattern Hình 33:Trước khi áp dụng CommandPattern public aspect ConcreteCommand extends CommandPattern { declare parents : TimedEvent implements CommandInvoker; declare parents : Printer implements CommandReceiver; declare parents : VCardPrinter implements CommandReceiver; declare parents : BusinessCard implements Command; public void BusinessCard.executeCommand(CommandReceiver receiver) { if (receiver instanceof Printer) { ((Printer) receiver).println(this.toString( )); } else { ((VCardPrinter) receiver).printVCard(this); } } public void executeCommand(CommandReceiver receiver) { ((Printer) receiver).println("Command triggered on printer receiver"); } protected pointcut commandTrigger(CommandInvoker invoker) : call(void TimedEvent.timedOut( )) && target(invoker); } Hình 34: Sử dụng CommandPattern trong ứng dụng Iterator pattern Iterator pattern cung cấp một cơ chế thi công tách biệt nhau của tập hợp các đối tượng, mà qua đó chúng được truy cập một cách tuần tự. Biến lặp hay con trỏ được dịch chuyển theo tập hợp các đối tượng trong khi giấu sự sắp xếp và thi công chi tiết của người dùng với tập hợp đó. Iterator pattern được sử dụng khi Cung cấp một cách thức đồng bộ, nhất quán để duyệt qua các thành phần của trong các danh sách đối tượng mà nó che giấu cách thực hiện thi công của từng danh sách đó. Hình 35: IteratorPatternAspect và interface định nghĩa vài trò của pattern public abstract aspect IteratorPattern { public interface Aggregate { public Iterator createIterator( ); public Iterator createReverseIterator( ); } } Ví dụ: public aspect EmployeeIteration extends IteratorPattern { declare parents : EmployeeCollection implements Aggregate; public Iterator EmployeeCollection.createIterator( ) { return new EmployeeIterator(this, true); } public Iterator EmployeeCollection.createReverseIterator( ) { return new EmployeeIterator(this, false); } } Hình 36: Mô tả sự tương tác của EmployeeIteration với ứng dụng Mediator pattern Mẫu thiết kế này giúp đơn giản quá trình trao đổi thông tin giữa các đối tượng trong hệ thống bằng các tạo một lớp quản lý các thông điệp phân tán giữa các đối tượng đó. Hình 37: Cấu trúc của MediatorPattern aspect public abstract aspect MediatorPattern { protected interface Colleague { } protected interface Mediator { } private WeakHashMap mappingColleagueToMediator = new WeakHashMap( ); private Mediator getMediator(Colleague colleague) { Mediator mediator = (Mediator) mappingColleagueToMediator.get(colleague); return mediator; } public void setMediator(Colleague c, Mediator m) { mappingColleagueToMediator.put(c, m); } protected abstract pointcut change(Colleague c); after(Colleague c) : change(c) { notifyMediator(c, getMediator(c)); } protected abstract void notifyMediator(Colleague c, Mediator m); } Ví dụ sử dụng Mediator pattern: public aspect DialogMediator extends MediatorPattern { declare parents : ListBox implements Colleague; declare parents : EntryField implements Mediator; protected pointcut change(Colleague c) : ( execution(void ListBox.setSelection(..)) && this(c)); protected void notifyMediator(Colleague c, Mediator m) { ListBox listBox = (ListBox) c; EntryField entryField = (EntryField) m; entryField.setText(listBox.getSelection( )); } } Hình 38: Trước và sau khi áp dụng Mediator pattern Chain of Responsibility Pattern Mẫu thiết kế này có ý nghĩa đúng như tên gọi của nó, được sử dụng để hỗ trợ chuỗi các hành động nối tiếp nhau trong hệ thống. Mỗi bước thực hiện được quản lý bởi một đối tượng và chịu trách nhiệm trên sự phân công chức năng của hệ thống. Hình 39: Cấu trúc của ChainOfResponsibilityPattern aspect public abstract aspect ChainOfResponsibilityPattern { protected interface Handler { } public WeakHashMap successors = new WeakHashMap( ); protected void receiveRequest(Handler handler, Object request) { if (handler.acceptRequest(request)) { handler.handleRequest(request); } else { // The handler will not accept the request Handler successor = getSuccessor(handler); if (successor == null) { // Last handler in the chain so must deal with the request // This is a rudimentary implementation and more complex // logic could be applied here or perhaps in the concrete // aspects that extend this abstract one handler.handleRequest(request); } else { // Hand the request on to the next successor in the chain receiveRequest(successor, request); } } } public boolean Handler.acceptRequest(Object request) { // The default as defined here is to reject the request // This is implemented by the application specific // concrete aspects return false; } public void Handler.handleRequest(Object request) { // A default empty implementation that is overridden // if required by the application specific concrete aspects } protected abstract pointcut eventTrigger(Handler handler, Object request); after(Handler handler, Object request) : eventTrigger(handler, request) { receiveRequest(handler, request); } public void setSuccessor(Handler handler, Handler successor) { successors.put(handler, successor); } public Handler getSuccessor(Handler handler) { return ((Handler) successors.get(handler)); } } Ví dụ sử dụng: Hình 40: Sau khi áp dụng ChainOfResponsibilityPattern public aspect HelpChain extends ChainOfResponsibilityPattern { declare parents : PrintButton implements Handler; declare parents : PrintDialog implements Handler; declare parents : Manager implements Handler; protected pointcut eventTrigger(Handler handler, Object event) : call(void PrintButton.doClick(..)) && target(handler) && args(event); private boolean Handler.alreadyHandledRequest = false; public boolean Handler.acceptRequest(Object event) { return !this.alreadyHandledRequest; } public void PrintButton.handleRequest(Object event) { if (!this.acceptRequest(event)) { System.out.println( "PrintButton Forced to handle Request" + "due to being last in the chain (Implementation Decision)"); } System.out.println("PrintButton handling request: " + event); this.alreadyHandledRequest = true; } public void PrintDialog.handleRequest(Object event) { if (!this.acceptRequest(event)) { System.out.println( "PrintDialog Forced to handle Request" + "due to being last in the chain (Implementation Decision)"); } System.out.println("PrintDialog handling request: " + event); this.alreadyHandledRequest = true; } public void Manager.handleRequest(Object event) { if (!this.acceptRequest(event)) { System.out.println( "Manager Forced to handle Request due to being" + "last in the chain (Implementation Decision)"); } System.out.println("Manager handling request: " + event); this.alreadyHandledRequest = true; } } Hình 41:Sử dụng ChainOfResponsibilityPattern trong ứng dụng Memento Pattern Mẫu thiết kế này cung cấp một cơ chế để trạng thái ban đầu của một đối tượng có thể được phục hồi sau một thời gian mà không cần gắn với một cơ chế cụ thể trong đó trạng thái của đối tượng được thiết lập lại với đối tượng. Memento đóng gói tất cả thông tin cần thiết để phục hồi trạng thái nội tại trước của một đối tượng tại thời điểm muộn hơn. Khả năng này có thể được sử dụng để áp dụng thao tác undo trạng thái đối tượng trong các ứng dụng cụ thể. public abstract aspect MementoPattern { public interface Memento { public void setState(Originator originator); public Object getState( ); } public interface Originator { public void setMemento(Memento memento); public Memento createMemento( ); public Object getState( ); } Hình 42: Cấu trúc của MementoPattern aspect. Ví dụ sử dụng Mememto: public aspect EmployeeMemento extends MementoPattern { declare parents : Employee implements Originator; public void Employee.setMemento(Memento memento) { Object object = memento.getState( ); Employee stateToRestore = (Employee) object; this.setName(stateToRestore.getName( )); this.setSalary(stateToRestore.getSalary( )); } public Memento Employee.createMemento( ) { Memento memento = new DefaultMemento( ); memento.setState(this); return memento; } public Object Employee.getState( ) throws MementoException { Employee employee = new Employee(this.getName( ), this.getSalary( )); return employee; } } Hình 43: Sử dụng MementoPattern trong ứng dụng Visitor Pattern Visitor Pattern trong mô hình OOP được sử dụng để thể hiện các hành động được thực hiện trên các thành phần của cấu trúc đối tượng. Visitor cho phép định nghĩa thêm các thao tác mà không cần thay đổi lớp của các thành phần mà nó thao tác trên đó. Với mô hình AOP, điều này không thực sự có ý nghĩa lắm vì bản chất của AOP chính là sự can thiệp vào các cấu trúc và hành vi của đối tượng. Hình 44: Cấu trúc của Visitor pattern aspect public abstract aspect VisitorPattern { public interface Element { public void accept(Visitor visitor); } public interface CompositeElement extends Element { public Element[] getElements( ); } public interface Result { } public interface Visitor { public void visitElement(Element element); public void visitComposite(CompositeElement element); public Result getResult( ); } public void CompositeElement.accept(Visitor visitor) { visitor.visitComposite(this); } public void Element.accept(Visitor visitor) { visitor.visitElement(this); } } Ví dụ sử dụng Visitor pattern: public aspect InventoryVisitor extends VisitorPattern { declare parents : FloppyDisk implements Element; declare parents : HardDisk implements Element; declare parents : Processor implements Element; declare parents : Computer implements CompositeElement; declare parents : Motherboard implements CompositeElement; declare parents : InventoryReport implements Result; public Element[] Computer.getElements( ) { Element[] elements = new Element[3]; elements[0] = this.getMotherboard( ); elements[1] = this.getHardDisk( ); elements[2] = this.getFloppyDisk( ); return elements; } public Element[] Motherboard.getElements( ) { Element[] elements = new Element[1]; elements[0] = this.getProcessor( ); return elements; } } Cấu trúc và quan hệ giữa các thành phần của Computeur Hình 45: Cấu trúc của Computeur Cấu trúc và quan hệ giữa các thành phần của Computeur sau khi áp dụng Visitor pattern Hình 46: Cấu trúc Computeur sau khi áp dụng Visitor pattern Hình 47:Sử dụng VisitorPattern trong ứng dụng Strategy pattern Strategy pattern cung cấp một cơ chế để tách biệt các lớp client từ sự thi công chi tiết của một thuật toán cụ thể hoặc một chiến lược nào đó. Thường thì tất cả các lớp riêng rẽ mà thi công strategy đã thi công một interface riêng để cho phép client được tách biệt ra với các thi công khác. public abstract aspect StrategyPattern { Hashtable strategyPerContext = new Hashtable( ); protected interface Strategy { } protected interface Context { } private Strategy Context.strategy = null; public void setConcreteStrategy(Context c, Strategy s) { strategyPerContext.put(c, s); } public Strategy getConcreteStrategy(Context c) { return (Strategy) strategyPerContext.get(c); } } Hình 48:Cấu trúc của StrategyPattern aspect Ví dụ áp dụng: public aspect SortingStrategy extends StrategyPattern { declare parents : Sorter implements Context; declare parents : LinearSorter implements Strategy; declare parents : BubbleSorter implements Strategy; int[] around(Sorter s, int[] numbers) : call(int[] Sorter.sort(int[])) && target(s) && args(numbers) { Strategy strategy = getConcreteStrategy(s); if (strategy instanceof BubbleSorter) ((BubbleSorter) strategy).sort(numbers); else if (strategy instanceof LinearSorter) ((LinearSorter) strategy).sort(numbers); return numbers; } } Hình 49: Cấu trúc các lớp sắp xếp khi chưa áp dụng StrategyPattern Hình 50: Cấu trúc các lớp sắp xếp sau khi áp dụng StrategyPattern Hình 51: Sử dụng Strategy Pattern trong ứng dụng State Pattern State Pattern cung cấp một cơ chế cho đối tượng có thể biến đổi hành vi của nó dựa trên các trạng thái của nó. public aspect TCPConnectionState { protected TCPState listening = new TCPListen( ); protected TCPState acknowledged = new TCPAcknowledged( ); protected TCPState closed = new TCPClosed( ); after(TCPConnection connection) : initialization(new ( )) && target(connection) { listening.setConnection(new SocketConnection( )); connection.setState(listening); } after(TCPConnection connection, TCPState state) : call( void TCPState +.acknowledge( )) && target(state) && this(connection) { if (connection.getState( ) == listening) { acknowledged.setConnection(listening.getConnection( )); connection.setState(acknowledged); } } after(TCPConnection connection, TCPState state) : call( void TCPState +.close( )) && target(state) && this(connection) { if ((connection.getState( ) == listening) || (connection.getState( ) == acknowledged)) { connection.setState(closed); } } } TCPConnectionState aspect cho thấy lớp TCPConnection sẽ được lắng nghe khi nó được tạo, được báo khi phương thức acknowledge() được gọi và đóng khi phương thức close() được gọi. Hình 52: Sử dụng state pattern trong ứng dụng Kết luận AOP đang thực sự trở thành phương pháp luận cho ngành công nghệ phần mềm hiện nay. AOP đã được đưa vào nhiều ngôn ngữ, và trên thực tế AOP đã được triểnkhai trên các ứng dụng thương mại như JBOSS application server phiên bản 4.0, Spring Framework và đã đạt được một số kết quả ban đầu trong việc triển khai một ứng dụng AOP cụ thể. Điểm mạnh của AOP là xây dựng các ứng dụng middleware bao gồm các thao tác phức tạp như security, tracing, loging, transaction. .. Đặc biệt trong công nghệ Enterprise Java Bean của Sun Microsystem, các nhà phát triển đã lên kế hoạch đưa AOP vào trong đặc tả phiên bản EJB 3.0 tiếp theo. AOP có phải là một cuộc cách mạng trong phương pháp lập trình hay không thì còn phải chờ vào những kết quả triển khai thực tế của các sản phẩm hỗ trợ AOP. Do thời gian có hạn, đồ án môn học này mới chỉ đi vào khía cạnh ngôn ngữ và việc xây dựng lại các mẫu thiết kế (design pattern) trong mô hình OOP chuyển sang mô hình AOP, tận dụng những đặc điểm mới của AOP. Đây là một trong những bước quan trọng trong việc đưa AOP vào áp dụng trong các ứng dụng cụ thể. Trong thời gian tới, đồ án sẽ tiếp tục đi sâu hơn nữa trong việc triển khai các ứng dụng cụ thể trên AOP, những khó khăn và thách thức cho phương pháp lập trình mới này Chúng em xin chân thành cảm ơn Thầy giáo Huỳnh Quyết Thắng đã định hướng và cung cấp những kiến thức cơ bản cũng như những tài liệu báu để em có thể hoàn thành tốt đồ án này. Tài liệu tham khảo Elements of Reusable Object-Oriented Software Addison Wesley - Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides - Addison Wesley, 1995 AspectJ CookBook- Russell Miles - O'Reilly 2004 AspectJ in Action-RAMNIVAS LADDAD-Manning publishing - 2004 Mastering AspectJ-Joseph D. Gradecki, Nicholas Lesiecki -Wiley publishing - Aspect Oreinted Software development community & conference

Các file đính kèm theo tài liệu này:

  • docAOP và AspectJ.doc