AOP solves the problem of tight coupling-Build a highly loose system with powerful static cross-cutting functions

Source: Internet
Author: User
Tags knowledge base
Build a highly loose system with powerful static cross-cutting functions

Level: Intermediate

Andrew GLOVER Aglover@vanwardtechnologies.com)
CTO, vanward Technologies
March 2004

Many Java developers have accepted the non-mandatory style and flexibility of Aspect-oriented programming (AOP), especially when it is used to build a highly loose and scalable enterprise system. In this article, you will see how one of the functional design concepts of AOP (static cross-cutting) converts a bunch of messy, tightly coupled code into a powerful, scalable enterprise application.

In the rapid development cycle that transforms business requirements into software functions, aspect orientation is a powerful design principle that can be used. By shifting the primary design focus from the traditional features of Object-Oriented Programming (OOP, AOP and design principles allow software architects to consider design in a way that is equivalent and complementary to object-oriented.

In this article, you will learn how to implement one of the most inadequate features of AOP. Crosscutting is a relatively simple design and programming technology with powerful power, especially when it is used to build loosely coupled, scalable enterprise systems. Although dynamic cross-cutting (the object's runtime behavior can be changed) is considered to be one of the foundations of AOP, static cross-cutting is a far unknown technology. I will try to make up for this defect in this article. I will first give an overview of dynamic and static cross-cutting, and then quickly jump into an implementation scenario to demonstrate the latter technology. You will personally experience how convenient static cross-cutting is to overcome one of the following most common enterprise challenges: how to maintain the flexibility of the application code library (codebase) While leveraging third-party code.

Note that although I first briefly outline Aspect-Oriented Programming in terms of concept, this article is not an introduction to AOP. See the references section for a list of introductory articles on this topic.

AOP Overview
The most fundamental charm of object-oriented design is that it can model entities and their behaviors in the real world as abstract objects. A system designed in an object-oriented way produces many effective business objects, suchPerson,Account,OrderAndEvent. The disadvantage of object-oriented design is that such business objects become chaotic due to mixed attributes and operations that are inconsistent with the object's original intent.

By enabling designers to use dynamic and static cross-cutting and adding object behavior in a non-mandatory neat and modular way, Aspect-oriented programming effectively solves this problem.

What is cross-cutting?
Cross-cuttingIt is a proprietary term for Aspect-Oriented Programming. It refers to operations that traverse established responsibilities (such as logging and performance optimization) in a given programming model. In the world of cross-cutting, there are two types of cross-cutting: Dynamic cross-cutting and static cross-cutting. In this article, although I will briefly discuss both, I mainly focus on static cross-cutting.

Dynamic cross-cutting
Dynamic cross-cuttingYesEntry PointAndConnection PointInAspectDuring the creation process, the connection points can be horizontally applied to existing objects during execution. Dynamic cross-cutting is usually used to help add logging or identity authentication to methods at the object level. Let's take a moment to understand some practical concepts in Dynamic cross-cutting:

  • Aspect (aspect)Similar to classes in Java programming languages. The aspect defines the entry point and notification (advice), and is compiled by the aspect compiler such as aspectj, so that the cross-cutting (including dynamic and static) is woven into (interweave) existing objects.

  • OneJoin point)Is an exact execution point in program execution, such as a method in the class. For example, ObjectFoo Method inbar()It can be a connection point.Connection PointIs an abstract concept; you do not need to define a connection point.
  • OnePointcut)Essentially a structure used to capture connection points. For example, you can define a starting point to capture objects.Foo Method inbar(). In contrast to the connection point, the start point must be defined in the aspect.
  • Advice)Is the executable code of the entry point. A commonly defined notification is to add the logging function, where the entry point captures the object Foo Inbar()Then, the notification dynamically inserts some logging functions, such as capturingbar().

These concepts are the core of Dynamic cross-cutting, although as we will see soon, they are not all necessary for static cross-cutting. For more information about Dynamic cross-cutting, see references.

Static cross-cutting
Static cross-cuttingThe difference from Dynamic cross-cutting is that it does not modify the execution behavior of a given object. Instead, it allows you to introduce additional method fields and attributes to modify the object'sStructure. In addition, you can append the extension and implementation to the basic structure of the object.

Although the general use of static cross-cutting cannot be discussed now-it seems to be a relatively unexplored (although very attractive) feature of AOP-the potential of this technology is enormous. With static cross-cutting, architects and designers can use a real object-oriented method to effectively build complex system models. Static cross-cutting allows you to insert common behaviors across the entire system in a more elegant and realistic way without creating a deep hierarchy.

In the remaining sections of this article, I will focus on the Technology and Application of Static cross-cutting.

Create static cross-cutting
The syntax for creating static cross-cutting is very different from that for Dynamic cross-cutting, that is, there is no entry point or notification. Specify an object (for exampleFoo), Static cross-cutting makes it easy to create a new method, add an additional constructor, or even change the inheritance hierarchy. We will use an example to better demonstrate how static cross-cutting is implemented in an existing class. Listing 1 shows a simple, non-facetedFoo.

Listing 1. No foo

public class Foo {      public Foo() {     super();   }}

As shown in Listing 2, adding a new method to an object is as simple as defining a method in one aspect.

Listing 2. Add a new method to foo

public aspect FooBar {     void Foo.bar() {      System.out.println("in Foo.bar()");   }}

The difference between constructors is thatnewKeywords are required, as shown in listing 3.

Listing 3. Add a new constructor to foo

public aspect FooNew {      public Foo.new(String parm1){     super();     System.out.println("in Foo(string parm1)");   }}

To change the inheritance level of an object,declare parentsLabel. For example,FooImplementRunnable, Or expandThread. Listing 4 showsdeclare parentsLabel to changeFoo.

Listing 4. Modifying the inheritance level of foo

public aspect FooRunnable {   declare parents: Foo implements Runnable;     public void Foo.run() {      System.out.println("in Foo.run()");   }}

Now, you may start imagining the meaning of static cross-cutting, especially when it comes to creating loosely coupled, highly scalable systems. In the following sections, I will show you how easy it is to use static cross-cutting to expand the flexibility of your enterprise applications.

Implementation scenario
Enterprise systems are often designed to use third-party products and libraries. To avoid coupling the entire structure with the required products, an abstraction layer is usually included in an application designed to interact with the code of an external vendor. When inserting implementations from other vendors or self-developed code, this abstraction layer provides a high degree of flexibility for the architecture with minimal damage to system consistency.

In this implementation scenario, it is assumed that the system will notify the customer through different communication channels after an operation occurs. In this example, the system usesEmailObject To represent an instance of Direct Email communication. As shown in listing 5,EmailThe object contains attributes such as the sender address, recipient address, topic bar, and message body.

Listing 5. Example email object

public class Email implements Sendable {   private String body;   private String toAddress;   private String fromAddress;   private String subject;   public String getBody() {return body;   }   public String getFromAddress() {return fromAddress;   }   public String getSubject() { return subject;   }   public String getToAddress() { return toAddress;   }   public void setBody(String string) { body = string;   }   public void setFromAddress(String string) { fromAddress = string;   }   public void setSubject(String string) { subject = string;   }   public void setToAddress(String string) {   toAddress = string;   }}

Integrate third-party code
In addition to setting up a custom communication system for sending emails, faxes, and short messages, the architecture team decides to integrate the product into a supplier, which can follow specific rules, send messages based on any object. This product is flexible and provides a ing mechanism through XML, allowing you to map custom client objects to specific channels with the vendor. The vendor's system relies heavily on this ing file and the reflection capability of the Java platform to work with common Java objects. To reflect flexibility, the architecture team has establishedSendableInterface model, as shown in Listing 6.

Listing 6. Example sendable Interface

public interface Sendable {   String getBody();   String getToAddress();}

Figure 1 showsEmailObject andSendableInterface Class diagram.

Figure 1. Class Diagram of email and sendable

Design challenges
In addition to the ability to send messages of different formats through different channels, the supplier provides a hook to allow recipient address verification through a given interface. The vendor's documentation indicates that any object implementing this interface will follow a predefined lifecycle.validateAddress()The method is called and the corresponding result behavior is correctly processed. IfvalidateAddress()ReturnfalseThe supplier's communication system will no longer attempt to communicate accordingly. Listing 7 shows the vendor'svalidateAddress()Interface.

Listing 7. Address verification for the sendable Interface

package com.acme.validate;public interface Validatable {      boolean validateAddress();}

Using basic object-oriented design principles, the architecture team decides to modifySendableInterface to expand the vendor'sValidatableInterface. However, this decision will result in direct dependency and coupling to the vendor code. If the development team decides to use another vendor's tool next, it will have to refactor the code library to delete it.SendableInterfaceextendsThe behaviors implemented in the statement and object layers.

A more elegant and fundamentally flexible solution is to use static cross-cutting to add behavior to the expected object.

Static cross-cutting brings assistance
Using the aspect-oriented principle, the team can create an aspect to declareEmailTarget Implementation of vendorValidatableIn addition, the architecture team codes the expected behavior inValidataAddress()Method. BecauseEmailThe object does not contain any supplier package import or definitionvalidateAddress()Method, so that the code can better eliminate coupling.EmailThe object does not realize that it isvalidatabl eType object! Listing 8 shows the results.EmailStatically reinforced to implement vendorValidatableInterface.

Listing 8. Email verifiable

import com.acme.validate.Validatable;public aspect EmailValidateAspect {   declare parents: Email implements Validatable;   public boolean Email.validateAddress(){     if(this.getToAddress() != null){   return true;     }else{   return false;     }   }}

Test it!
You can use JUnit to proveEmailValidateAspectActually changedEmailObject. In a JUnit test suite,EmailThe object can be created by default, and a series of test cases can be verified.EmailIndeedValidatableIn addition, you can use a test case to assert that iftoAddressIsnullvalidateAddress()Will returnfalse. In addition, another test case can be used to test whether a non-nullOftoAddressWill causevalidateAddress()Returntrue.

1-2-3. Use JUnit for testing.
You can first create a structure with simple values.EmailObject instance. Note that in listing 9, this instance does have a validnul)toAddressValue.

Listing 9. JUnit setup ()

import com.acme.validate.Validatable;public class EmailTest extends TestCase { private Email email; protected void setUp() throws Exception {   //set up an email instance   this.email = new Email();   this.email.setBody("body");   this.email.setFromAddress("dev@dev.com");   this.email.setSubject("validate me");   this.email.setToAddress("ag@ag.com"); } protected void tearDown() throws Exception {   this.email = null; }//EmailTest continued...}

For a validEmailObject,estEmailValidateInstanceof()Make sure the instance isValidatableType, as shown in listing 10.

Listing 10. JUnit verification instance

public void testEmailValidateInstanceof() throws Exception{    TestCase.assertEquals("Email object should be of type Validatable",     true, this.email instanceof Validatable); }

As shown in listing 11, the next test case intentionallytoAddressSet the fieldnullAnd then testvalidateAddress()Returnsfalse.

Listing 11. JUnit null toaddress check

public void testEmailAddressValidateNull() throws Exception{      //force a false   this.email.setToAddress(null);   Validatable validtr = (Validatable)this.email;      TestCase.assertEquals("validateAddress should return false",       false, validtr.validateAddress());}

The last step is for the sake of stability:testEmailAddressValidateTrue()Test CaseEmailInstance Initial Value callvalidateAddress(), That istoAddressThe value of the domain is the ag@ag.com.

Listing 12. JUnit non-null toaddress check

public void testEmailAddressValidateTrue() throws Exception{      Validatable validtr = (Validatable)this.email;   TestCase.assertEquals("validateAddress should return true",       true, validtr.validateAddress());}

Refactoring this example
The architecture team tries their best to useSendable Abstract Communication implementation. However, their first attempt seems to have ignored this interface. Cross-user from staticEmailAfter learning from the object, they raise the contractual behaviorSendableTo further refine the policy.

A supplier is created for the new aspect.ValidatableInterfaceSendableInterface. In addition, they created the implemented behavior in the aspect. This time,validateAddress()The method is defined for another communication object:Fax, As shown in listing 13.

Listing 13. A better aspect

import com.acme.validate.Validatable;public aspect SendableValidateAspect {   declare parents: Sendable extends Validatable;   public boolean Email.validateAddress(){          if(this.getToAddress() != null){       return true;     }else{       return false;     }   }   public boolean Fax.validateAddress(){      if(this.getToAddress() != null     && this.getToAddress().length() >= 11){        return true;     }else{        return false;     }  }}

Never stop refactoring
You may notice a slight deficiency in listing 13 because allSendableThe implementers are defined in the same aspect.validateAddress()Method. This can easily lead to code expansion. In addition, if you do not proceed with caution, changing the static structure of an interface will lead to many undesirable side effects: You must find all the implementers of the Target Interface. Therefore, the lesson here is simple: Never stop refactoring.

Conclusion
Although the API example here is artificial, it is expected to prove how simple static cross-cutting is to be applied in the enterprise architecture. Static cross-cutting is particularly effective in the scenario described in this article (it can be used to forcibly change the behavior or even define the object), but it has many other uses. For example, you can use static cross-cutting during development to "EJB" pojo (a traditional common Java object ); alternatively, you can use it in a business object to use the lifecycle interfaces of Persistence frameworks such as Hibernate (see references ).

Static cross-cutting provides an elegant solution for many minor defects that affect the effectiveness of enterprise code. Through this article, you have learned the basic knowledge of this technology and one of its most basic applications. See references to learn more about Aspect-Oriented Programming and other cross-cutting technologies.

References

  • Download the source code used in this article.

  • You can download aspectj and related tools from eclipse.org/aspectj. The website also contains a FAQ, email list, brilliant documentation, and links to other resources about AOP, which is a good place to start further research.
  • Aspectwerkz is a dynamic, lightweight, and high-performance AOP/aosd framework for the Java platform.
  • Eclipse IDE provides a special aspectj plug-in.
  • To obtain comprehensive information resources for aspect-oriented software development, try aosd.net.
  • The JBoss team has created an interesting AOP framework.
  • Hibernate is a powerful, ultra-high-performance object/relational persistence and query service for the Java platform.
  • Codehaus is a large knowledge base that contains many interesting open-source projects, including aspectwerkz and Nanning (another aspect implementation for the Java platform ).
  • Access developer bookstore for a comprehensive list of technical books, includingAspect-Oriented Programming with aspectj(SAMS Publishing, 2002) and ramnivas laddadAspectj in action(Manning Publishing, 2003) and a large number of other Java-related books.
  • In the developerworks Java technology area, you can find articles on various aspects of Java programming.
  • You can also go to the Java tutorial homepage on developerworks to get a detailed list of free tutorials for Java.

About the author
Andrew Glover is the CTO of vanward technologies, a company located in the city center of Washington, DC specializing in the Construction of automated testing frameworks to reduce the number of bugs in the software, reduces the number of integration and tests and improves the overall code stability.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.