项目作者: ezequieljuliano

项目描述 :
Concepts of aspect-oriented programming (AOP) in Delphi.
高级语言: Pascal
项目地址: git://github.com/ezequieljuliano/Aspect4Delphi.git
创建时间: 2015-05-22T18:30:08Z
项目社区:https://github.com/ezequieljuliano/Aspect4Delphi

开源协议:Apache License 2.0

下载


Aspect For Delphi

The Aspect4Delphi consists of an library that enables the use of the concept of aspect-oriented programming (AOP) in Delphi.

About The Project

AOP is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to existing code without modification of the code itself. Instead, we can declare this new code and these new behaviors separately.

Aspect4Delphi helps us implement these cross-cutting concerns.

Types of Advice

  • Before advice: advice that executes before a join point, but which does not have the ability to prevent execution flow proceeding to the join point (unless it throws an exception).
  • After advice: advice to be executed after a join point completes normally: for example, if a method returns without throwing an exception.
  • Exception advice: Advice to be executed if a method exits by throwing an exception.

Built With

Getting Started

To get a local copy up and running follow these simple steps.

Prerequisites

To use this library an updated version of Delphi IDE (XE or higher) is required.

Installation

Clone the repo

  1. git clone https://github.com/ezequieljuliano/Aspect4Delphi.git

Add the “Search Path” of your IDE or your project the following directories:

  1. Aspect4Delphi\src

Usage

To provide the aspect orientation paradigm in your project with Aspect4Delphi you need:

  • Implement a pointcut attribute.
  • Implement a class that represents your aspect.
  • Register your pointcut attribute and its aspect class in context.
  • Set your classes methods to virtual.
  • Write down your methods with the respective aspect.

Sample

To illustrate usage let’s look at a solution for managing logs of an application.

Implement a pointcut attribute (preferably inherits from AspectAttribute):

  1. interface
  2. uses
  3. Aspect.Core;
  4. type
  5. LoggingAttribute = class(AspectAttribute)
  6. private
  7. { private declarations }
  8. protected
  9. { protected declarations }
  10. public
  11. { public declarations }
  12. end;
  13. implementation
  14. end.

Implement the class that represents your aspect and contains the advices methods (you must implement the IAspect interface):

  1. interface
  2. uses
  3. System.SysUtils,
  4. System.Rtti,
  5. Aspect,
  6. Aspect.Core,
  7. Logging.Attribute,
  8. App.Context;
  9. type
  10. ELoggingAspectException = class(Exception)
  11. private
  12. { private declarations }
  13. protected
  14. { protected declarations }
  15. public
  16. { public declarations }
  17. end;
  18. TLoggingAspect = class(TAspectObject, IAspect)
  19. private
  20. { private declarations }
  21. protected
  22. procedure OnBefore(
  23. instance: TObject;
  24. method: TRttiMethod;
  25. const args: TArray<TValue>;
  26. out invoke: Boolean;
  27. out result: TValue
  28. ); override;
  29. procedure OnAfter(
  30. instance: TObject;
  31. method: TRttiMethod;
  32. const args: TArray<TValue>;
  33. var result: TValue
  34. ); override;
  35. procedure OnException(
  36. instance: TObject;
  37. method: TRttiMethod;
  38. const args: TArray<TValue>;
  39. out raiseException: Boolean;
  40. theException: Exception;
  41. out result: TValue
  42. ); override;
  43. public
  44. { public declarations }
  45. end;
  46. implementation
  47. { TLoggingAspect }
  48. procedure TLoggingAspect.OnAfter(instance: TObject; method: TRttiMethod;
  49. const args: TArray<TValue>; var result: TValue);
  50. var
  51. attribute: TCustomAttribute;
  52. begin
  53. inherited;
  54. for attribute in method.GetAttributes do
  55. if attribute is LoggingAttribute then
  56. begin
  57. LoggingFile.Add('After the execution of ' +
  58. instance.QualifiedClassName + ' - ' +
  59. method.Name
  60. );
  61. Break;
  62. end;
  63. end;
  64. procedure TLoggingAspect.OnBefore(instance: TObject; method: TRttiMethod;
  65. const args: TArray<TValue>; out invoke: Boolean; out result: TValue);
  66. var
  67. attribute: TCustomAttribute;
  68. begin
  69. inherited;
  70. for attribute in method.GetAttributes do
  71. if attribute is LoggingAttribute then
  72. begin
  73. LoggingFile.Add('Before the execution of ' +
  74. instance.QualifiedClassName + ' - ' +
  75. method.Name
  76. );
  77. Break;
  78. end;
  79. end;
  80. procedure TLoggingAspect.OnException(instance: TObject; method: TRttiMethod;
  81. const args: TArray<TValue>; out raiseException: Boolean;
  82. theException: Exception; out result: TValue);
  83. var
  84. attribute: TCustomAttribute;
  85. begin
  86. inherited;
  87. for attribute in method.GetAttributes do
  88. if attribute is LoggingAttribute then
  89. begin
  90. LoggingFile.Add('Exception in executing ' +
  91. instance.QualifiedClassName + ' - ' +
  92. method.Name + ' - ' +
  93. theException.Message
  94. );
  95. Break;
  96. end;
  97. end;
  98. end.

Register your pointcut attribute and its aspect class in context (preferably keep this context in singleton instance):

  1. interface
  2. uses
  3. Logging.Aspect;
  4. Aspect.Context;
  5. function AspectContext: IAspectContext;
  6. implementation
  7. var
  8. AspectContextInstance: IAspectContext = nil;
  9. function AspectContext: IAspectContext;
  10. begin
  11. if (AspectContextInstance = nil) then
  12. begin
  13. AspectContextInstance := TAspectContext.Create;
  14. AspectContextInstance.RegisterAspect(TLoggingAspect.Create);
  15. end;
  16. Result := AspectContextInstance;
  17. end;
  18. end.

In your business rule class use the attribute to define your joins points. You can use the constructor and destructor to add your class at the Weaver.

  1. interface
  2. uses
  3. System.SysUtils,
  4. Logging.Attribute,
  5. App.Context;
  6. type
  7. EWhatsAppMessageException = class(Exception)
  8. private
  9. { private declarations }
  10. protected
  11. { protected declarations }
  12. public
  13. { public declarations }
  14. end;
  15. TWhatsAppMessage = class
  16. private
  17. { private declarations }
  18. protected
  19. { protected declarations }
  20. public
  21. constructor Create;
  22. destructor Destroy; override;
  23. [Logging]
  24. procedure Send; virtual;
  25. end;
  26. implementation
  27. { TWhatsAppMessage }
  28. constructor TWhatsAppMessage.Create;
  29. begin
  30. inherited Create;
  31. AspectContext.Weaver.Proxify(Self);
  32. end;
  33. destructor TWhatsAppMessage.Destroy;
  34. begin
  35. AspectContext.Weaver.Unproxify(Self);
  36. inherited Destroy;
  37. end;
  38. procedure TWhatsAppMessage.Send;
  39. begin
  40. //Execution of send.
  41. end;

Roadmap

See the open issues for a list of proposed features (and known issues).

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

Distributed under the APACHE LICENSE. See LICENSE for more information.

Contact

To contact us use the options:

https://github.com/ezequieljuliano/Aspect4Delphi