Establish a highly loose system with a static cross cut
Level: Intermediate
Andrew Glover
(Aglover@vanwardtechnologies.com) CTO, Vanward Technologies 2004 March
Many Java developers have accepted non-mandatory styles and flexibility facing aspective programming (AOP), especially when used to establish a highly loose and scalable enterprise system. In this article, you will see one of the functional design concepts of the AOP (static cross-cut) how to turn the tightly coupled code that may be a big pile of chaos into a powerful, scalable enterprise application.
In the rapid development cycle of converting business needs into software features, aspect is a powerful design principle that can be utilized. The AOP and design principles allow software architects to design with an object-oriented approach to design. In this article, you will learn how to implement one of the most fully utilized features in AOP. Crosscutting is a relatively simple design and programming technology containing powerful strength, especially when it is used to establish a loosely coupled, expandable enterprise system. Although dynamic transverse (in which the operation of the object can be changed) is considered to be one of the foundations of AOP, but static cross cut is a technology that is far from knowing. I will try to make up this shortage in this article. I will first outline the dynamics and static crossings, and then quickly cut into a scene to show the latter technology. You will personally experience how conveniently overcome one of the most common business challenges as follows: How to maintain the flexibility of the application code library (Codebase) while using third-party code. Please note that although I first briefly program the concept aspect from the concept, this article is not an introduction to AOP. See Resources section to get a list of introductory articles about this topic. AOP Overview The most fundamental charm of object-oriented design is that it can model entities and their respective behavior in real-world domains as abstract objects. A multi-effective business objects are produced in systems-oriented systems, such as Person, Account, Order, and Event. A disadvantage of object-oriented design is that such business objects become confusing because of the mixed properties and operations that are inconsistent with the object. By using dynamic and static cross cuts, add object behavior with a non-strong neat and modular approach, which is effectively solved the problem. What is cross? Crossing is a proprietary noun for aspect. It refers to the operation of crossing the established responsibilities in a given programming model (such as logging and performance optimization). There are two types in cross-cutting world: dynamic transverse and static cross cut. In this article, although I will discuss it simultaneously, I mainly pay attention to static cross. Dynamic cross-cutting dynamics is the process of creating behaviors in one aspect by cutting points and connection points, and the connection point can be applied laterally to existing objects laterally. Dynamic transverse is often used to help add logging or authentication to various methods in the object hierarchy. Let us take some time to learn some practical concepts in dynamic cross:
Aspect (aspect) is similar to the class in the Java programming language. Aspects Define the entry point and notification (advice) and compiler, such as aspectj, to compile transverse (including dynamic and static) in an existing object of the interweave. A Join Point is a program execution point, such as one of the classes. For example, the method BAR () in the object foo can be a connection point. The connection point is an abstract concept; no connection point is defined without active. An entry point (Pointcut) is nature a structure for capturing connection points. For example, an entry point can be defined to capture all calls to the method BAR () in the object foo. In contrast to the connection point, the entry point needs to be defined in terms of aspect. Notification (Advice) is an executable code of the entry point. A frequently defined notification is to add a logging feature, where the entry point captures each call to the BAR () in the object foo, and then the notification is dynamically inserted into some logging functions, such as capturing the parameters of BAR (). These concepts are the core of dynamic cross, although as we are about to see, they are not necessarily a static cross. Please refer to the reference to learn more about dynamic cross cuts. The distinction between static transverse static transverse and dynamic cross is that it does not modify the execution behavior of a given object. Instead, it allows the structure of the object to be modified by introducing additional method fields and attributes. In addition, static crossings can be attached and implemented to the basic structure of the object. Although it is now unable to talk about static cross-cutting - it looks a relatively unpredictable characteristic of AOP (although very attractive) characteristics - however, this technology is huge. Using static cross cuts, architects and designers can effectively establish a model of complex systems with a truly object-to-object method. Static cross-cutting allows you to insert a public behavior across the entire system in an essentially more elegant, more elegant, more elegant, more realistic. In the rest of this article, I will focus on the technical and application of static cross cuts. Creating a static cross-cutting grammar and dynamic cross cuts are very different, that is, there is no entry point and notification. Given an object (such as the foo defined below), static crossings make the new method, add additional constructor, and even change the inheritance hierarchy. We will use an example to better show how static crossings are implemented in an existing class. Listing 1 shows a simple and unified foo. Listing 1. No aspect foopublic class foo {
Public foo () {
Super ();
}
}
As shown in Listing 2, add a new method in an object and define a method in one aspect is equally simple. Listing 2. Add a new method to foo
Public aspect foobar {
Void foo.bar () {
System.out.println ("in foo.bar ()");
}
}
The constructor is slightly different, where the NEW keyword is 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));
}
}
Changing the inheritance level of the object requires a Declare PARENTS tag. For example, in order to become multi-threaded, the foo will need RunNable, or extend Thread. Listing 4 shows the inheritance hierarchy of the Foo with the Declare Parents label. Listing 4. Change the inheritance level of foo PUBLIC Aspect foorunnable {
Declare parents: foo importments runnable;
Public void foo.run () {
System.out.println ("in foo.run ()");
}
}
Now, you may start to envision of static cross-cutting, especially when you are related to creating loosely coupled, highly scalable systems. In the following sections, I will take you to a real design and achieve scene to show how easy it is to expand the flexibility of your business application using static cross. Implementing the Scene Enterprise System is often designed to use third-party products and libraries. In order not to couple the entire structure and the required product, it is usually included in an application to interact with external vendor code to include an abstraction layer. When inserted into the implementation of other vendors and the self-developed code, this abstraction layer provides a high degree of flexibility to the architecture in the case where the system is destroyed. In this scenario, it is envisioned that the system notifies the customer by different communication channels after a certain operation. This example system uses an email object to represent an instance of direct email communication. As shown in Listing 5, the Email object contains properties such as sender addresses, recipient addresses, subjectors, and message body. Listing 5. Example Email object
Public class email imports sendable {
PRIVATE STRING BODY;
PRIVATE STRING TOADRESS;
PRIVATE STRING.
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;
}
}
In addition to establishing a custom communication system that sends an email, fax, short message, etc., the architecture team decided to integrate a supplier's product, which can follow a specific rule to send a message based on any object. . This product is very flexible and provides a mapping mechanism through XML, allowing custom client objects to be mapped to a particular channel with vendors. The manufacturer's system relies on this mapping file and the reflexibility of the Java platform to work with ordinary Java objects. In order to reflect the flexibility, the architecture team has established a Sendable interface model, as shown in Listing 6. Listing 6. Example Sendable interface
Public interface sendable {
String getBody ();
String gettoAddress ();
}
Figure 1 shows the class diagram of the Email object and the sendable interface. Figure 1. Email and Sendable Class Diagrams Design Chart In addition to the ability to send a variety of formats through different channels, the supplier provides a hook (hook) to allow recipient address authentication. The supplier's document shows that any object that implements this interface will follow a predefined lifecycle, and its validateAddress () method will be called and correctly handle the corresponding result behavior. If ValidateAddress () returns false, the vendor's communication system will no longer try to carry out the corresponding communication. Listing 7 shows the supplier's validateAddress () interface. Listing 7. Address verification of sendable interface
Package com.acme.validate;
Public interface validatable {
Boolean ValidateAddress ();
}
Using basic object-oriented design principles, the architecture team decided to modify the Sendable interface to extend the vendor's ValidAtable interface. However, this decision will lead to direct dependent and coupling of supplier code. If the development team will decide to use another supplier's tool, you have to reconstruct the code base to delete the Extends statements in the Sendable interface and the active behavior in the object level. A more elegant and fundamentally flexible solution is to use static crossings to add behavior to expected objects. Static cross-cutting brought the use of aspect-oriented principles, which can create an aspect to declare the Email object to implement the vendor's ValidAble interface; in terms of aspect, the architecture team encodes the expected behavior in the validataAdDress () method. Because the Email object does not contain any supplier's import, no validateAddress () method is defined, so that the code is better eliminated. The Email object is not realized at all, which is the object of the ValidataBl E type! Listing 8 shows the results, where Email is static to enhance the ValidAtable interface of the supplier. Listing 8. Email verifiable
Import com.acme.validate.validatable;
Public aspect emailvalidateaspect {
Declare PARENTS: Email Implements Validatable;
Public boolean email.valideaddress () {
IF (this.gettoaddress ()! = null) {
Return True;
} else {
Return False;
}
}
}
have a test! You can use JUnit to prove that EmailValidateAspect has indeed changed the email object. In a JUnit test kit, the email object can be created with default values, and then a series of test cases can verify an instance of Validatable; in addition, it can be asserted by a test case if toaddress is NULL, ValidateAddress () The call will return false. In addition, another test case can be used to test: a non-null toadDress will cause validateAddress () to return True. 1-2-3, tested with JUnit You can first create such a structure, which constructs an Email object instance with a simple value. Note In Listing 9, this instance does have a TOADDRESS value that is valid (means non-NUL). 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 Continue ...
}
For an effective Email object, EstemailValidateInstanceOf () Make sure the instance is a validatable type, as shown in Listing 10. Listing 10. JUnit check instance
Public void testemailvalidateIdateIndAnsTanceOf () 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 deliberately set the toaddress field to NULL, and then verify that validateAddress () will return false. 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 final step is for robust consideration: TestemailDressValidatetrue () Test cases call validateaddress () with an Email instance, the value of the toaddress domain is Ag@ag.com. Listing 12. JUnit is non-NULL toADDress check
Public void TestemailaddressValidatetrue () THROWS Exception {
ValidATable Validtr = (Validatable) this.email;
Testcase.assertequals ("ValidateAddress Should Return True,
True, Validtr.ValidateAddress ());
}
Reconstructing this example architecture team wants to use the Sendable interface to abstract communication; however, their first attempt seems to ignore this interface. After absorbing lessons from the static cross-cutting people Email object, they further refine their strategies by upgrading contract behaviors in the object level to the Sendable base. The new aspect creates an extension of the sendable interface with the vendor's ValidAtable interface. In addition, they create implemented behaviors in terms of respect. This time, the validateaddress () method is to define: Fax, as shown in Listing 13 for another communication object. Listing 13. A better aspect import com.Acme.validate.validatable;
Public aspect sendableValidateAspect {
Declare Parents: Sendable Extends Validatable;
Public boolean email.valideaddress () {
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 reconstructing that you may notice that in Listing 13 is slightly unpleasant, because all Sendable implementers each have the validateAddress () method defined in the same aspect. This is easy to cause the code to expand. In addition, if you don't care, change the static structure of an interface will have a lot of undesired side effects: all the implementors of the target interface must be found. Therefore, the lessons here are simple: never stop reconstruction. Although the API example here is human, it is expected to prove how simple is to apply static cross cuts in the enterprise architecture. Static transverse is applied to this type of scenario described herein (it can be used in unmodified behavior or even definitions), but it still has many other uses. For example, you can use static cross-cut "EJB" POJO (traditional ordinary Java object) when developing; or you can use it in business objects to use a lifecycle interface such as Hibernate (see Resources) ). Static crossing provides an elegant solution for many slight defects that affect the effectiveness of the corporate code. Through this article, you have learned the basics of this technology and one of its most basic applications. See Resources to learn more about facing aspects of programming and other cross-cutting technologies. Reference
Download the source code used herein. You can download AspectJ and its related tools from Eclipse.org/aspectj. The site also includes a FAQ, mailing list, a wonderful document, and links to other resources of AOP, a great place to further study. AspectWerkz is a dynamic, lightweight and high-performance AOP / AOSD framework for Java platforms. Eclipse IDE provides an AspectJ plugin. To obtain a comprehensive information resource development, try a comprehensive information, 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 Java platforms. CodeHaus A large-scale knowledge base containing a lot of interesting open source projects, including AspectWerkz and Nanning (another aspect implementation for Java platform). Visit the Developer Bookstore to obtain a comprehensive list of technical books, including Ivan Kiselev of Aspect-Oriented Programming with AspectJ (Sams Publishing, 2002) and Ramnivas Laddad of AspectJ in Action (Manning Publishing, 2003), as well as other large number of Java-related books . About the article about Java programming is available in the developerWorks Java technology zone. You can also browse the Java Technology Access Tutorial Homepage from DeveloperWorks to get a detailed list of free tutorials for Java. About the author Andrew Glover is the Chief Technology Officer (CTO) of Vanward Technologies. The company is a company in Washington DC city, specializing in the construction of automatic test framework to reduce the number of bugs in software, reduce integration and testing, and Improve overall code stability.