A convenient representation for an architecture adapter is a single component with a set of requirements on it and the boundary interfaces that the requester expects to see. This leaves the details of the mediation between the two architectures to a lower level of design and implementation (see Figure 4-1).
The low-level design and implementation of an architecture adapter is a bit more involved. Designs will be radically different based on the architectures involved, how reusable and generic the architecture adapter will be, and the facilities readily available for doing the necessary conversions between the architectural styles. The closer the match between the source and target architectures, the thinner and easier it is to write the architecture adapter. Conversely, the further apart that the source and target architectures are, the more complex and difficult it is to write the adapters.
Three components make up the structure of a complete solution. A single component, the ArchitectureAdapter , holds the responsibilities of mediating between the two architectures involved. The three components are as follows :
ArchitectureAComponent: The A component implements functionality in a particular architectural style. For example, it may implement its functionality using the Java platform and, therefore, use an object- oriented, call-return architectural style.
ArchitectureBComponent: The B component implements complementary functionality in a different architectural style than the A component. Most likely, the complementary functionality did not occur in a preplanned fashion. Instead, the A and B component are often purchased functionality in different software upgrade cycles. For example, a company purchased the A component as it installed an Enterprise Resource Planning (ERP) system and purchased the B component when it decided it needed a Customer Relationship Management (CRM) solution to facilitate its growing customer base.
ArchitectureAdapter: The architecture adapter mediates between the two architecture styles inherent in the ArchitectureAComponent and the ArchitectureBComponent . To mediate properly, the adapter must offer a natural interface to both components, regardless of the complexities of mediating the service interaction. The implementation must convert one component's architecture entirely to the other component's architecture and maintain the behavior and expectations of both clients . To do this, data styles must be mapped properly, differences in the behavior of communications must be mapped properly, and even such complexities as converting a rich object hierarchy to a flat component interface must be achieved gracefully.
Frequently, the architecture adapter splits into two halves, one that communicates directly with the A component and one that communicates directly with the B component. The two halves then implement their own architectural style to communicate with each other, as shown in Figure 4-2.
In Figure 4-2, ClientAdapterA and ClientAdapterB make up the entire functionality of the ArchitectureAdapter . By splitting the ArchitectureAdapter into halves, it becomes easier to add a third component type into the mix. Without the intermediate architecture style, you must build two new architecture adapters ”one to communicate with each of the existing components. With this modified design, you can build a single adapter to communicate into the intermediate architectural style. Welcome to one of the primary motivations for the Web Service architecture: a mechanism to provide mediation between different architectural styles. Web Services implement the Architecture Adapter pattern in such a way that it is simple to mine differing architectures for functionality.
The interesting part of the collaborations between components is in the call style and the data structures passed between components. Instead of using the first structuring from Figure 4-1, I use the second structuring from Figure 4-2 to show a sequence that more closely resembles a Web Service scenario. Figure 4-3 shows the sequence of operations for component A to make a call against component B.
The call between component instance A and clientAdapterA takes place in the operational call style inherent in the A architecture and with data structures native to the A architecture. The first client adapter converts the call to a neutral third architectural style and makes a call in this third style with the appropriate data structures to the second client adapter. This second client adapter converts the operation to B 's architectural style and makes the call to the B component with data structures and a call style native to the B architecture.