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
66 trang |
Chia sẻ: netpro | Lượt xem: 2581 | Lượt tải: 4
Bạn đang xem trước 20 trang tài liệu Đề tài AOP và AspectJ, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
hươ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
Các file đính kèm theo tài liệu này:
- AOP và AspectJ.doc