Friday, April 10, 2020

Design Patterns - Adapters and Wrappers

What is an adapter and how do I use it?

The adapter, as its name implies, describes a solution to the problem of making two disparate interfaces compatible by acting as a translation mechanism between them.
How do I recognize where I need an adapter?
The formal definition of the adapter, as given by “Design Patterns, Elements of Reusable Object-Oriented Software” by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides is:
Convert the interface of a class into another interface clients expect
The need for an adapter usually results from modifications or enhancements to class libraries or COM components. For example, re-factoring can often result in significant changes to the way in which the interface for a class needs to be defined. This in turn may necessitate major changes in application code that calls on the services of such classes. Making such changes is always a high risk option and should be avoided wherever possible
One solution, when source code is available is to retain the methods in the original interface to the class, but remove the implementation into new methods. The old methods are then left as “control” methods that no longer do the real work, instead they manage the calls to other methods. However, this still requires that existing code be modified.
The alternative is to create a new class which replicates the expected interface and translates calls to that interface into the correct format for the replacement. When dealing with components to which the source code is not available, this is the only method of dealing with changes to their interface.
What are the components of an adapter?
An adapter has two essential requirements. First we need a class that defines the interface that is to be adapted, the “adaptee”. Second, we need the “adapter” class that defines the expected interface, and maps the methods in that interface to those defined by the adaptee. The client calls one of the ‘expected’ methods, which is exposed on one side of the adapter, which simply passes the method call on to the appropriate method in the adaptee.
How do I implement an adapter?
In other languages an adapter is typically implemented using multiple inheritance by creating a sub class of the adaptee that inherits the implementation methods privately, and allowing it to also inherit the public interface from the class that defines the required interface.
This presents somewhat of a problem in Visual FoxPro because it does not support the multiple inheritance which is required to do it this way. A feature that was introduced in Visual FoxPro 7.0 is the IMPLEMENTS keyword that allows a Visual FoxPro class, defined in code, to inherit an interface that is defined in a type library. However, because it relies on type libraries it can only be used with COM components, and not with native Visual FoxPro classes, so it is not really much help in this context.
The best way to implement an adapter in Visual FoxPro is to create a class which exposes the methods of the expected interface, and holds an object reference to the adaptee. Client objects can then call their expected methods that in turn translate the call to the appropriate method on the adaptee. The result is that in VFP there is little difference between an adapter and a decorator except in terms of the intent. A decorator modifies behavior, while an adapter only modifies an interface.
Adapter pattern summary
The adapter pattern is used to avoid the necessity for changing code when an interface is changed, or to allow for future modifications or implementations when designing generic classes. However, because Visual FoxPro does not support multiple inheritance, the only practical implementation mechanism available is identical to that used by the Decorator.
What is a wrapper, and how do I use it?
Now that is a very good question indeed! If you study “Design Patterns, Elements of Reusable Object-Oriented Software” by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides you will not find a pattern named ‘wrapper’ anywhere in the list of primary patterns. However, a more diligent search of that resource will reveal that it is actually listed as a synonym for both the Adapter and Decorator patterns.
Now this does not make much sense to us. If “wrapper” really is a synonym for both, then logically they are also synonyms for each other and it follows that all three terms must refer to the same pattern – after alkl it is axiomatic that:
IF a = b AND b = c THEN a = c
Yet this is clearly not the case! As we have seen, Decorator and Adapter are quite different in their intent, and any similarities in their implementation are (as always) irrelevant in the context of a pattern’s definition. Whilst not wishing to disagree with the authors of the book we feel that, in this particular case at least, they have it wrong.
It seems to us that since the word “wrapper” actually means a covering, that to describe either the decorator or the adapter as “wrappers” is also semantically inaccurate. Both of these patterns rely on fooling the client into believing that an interposed object is actually the intended target by having it look like the object that the client expects. They may, therefore, both be “mimics”, or “impersonators”, but they are not really wrappers!
So, where would I use a wrapper?
We take the view that the intent of a wrapper is to manage the content.  As part of that function it may, but does not have to, include the functions provided by either, or both, the Decorator or the Adapter. Wrappers provide a means of integrating functionality that is not defined in objects into a an object-oriented environment.
What are the components of a wrapper?
A wrapper has two essential requirements. First we need an implementation that defines the functionality that we wish to access. This may, or may not be an object (one example of a non-object implementation would be a DLL whose functions we need to access). Second, we need the “wrapper” class that provides an object interface to access the implementation and methods to manage the implementation. The client calls a method on the wrapper which access the implementation as needed to fulfill the request.

 The following definitions summarize how we might differentiate between Wrappers, Decorators and Adapters which, as we have seen, are all implemented using the same basic structure:
·         Decorator            Modify behavior, without modifying an existing interface
·         Adapter       Modify interface without modifying behavior
·         Wrapper      Provide interface for, and services to, behavior that is defined elsewhere
How can I implement a wrapper?
It seems to us that most of the classes that we see referred to as ‘managers’ in VFP are actually wrappers. For example a form manager that creates and releases forms, manages a forms collection and provides an interface for accessing running forms is, by our definition above, an example of a wrapper. The distinction in name may be because it’s dealing with objects but that doesn’t alter the intent.
Another example of a wrapper would be a class to access the functions of Windows Shell DLLs. Such a class includes methods for checking that the required DLL is actually available, that it’s the correct version and is properly registered. The wrapper is also responsible for releasing the DLL from memory when it is finished with.
Wrapper pattern summary
Wrapper is clearly a pattern in its own right, and differs in intent from both Decorator and Adapter (to which it is closely allied in many VFP implementations). Wrappers provide management functions as well as access, to components that deliver functionality to an application as if they were VFP Objects – whether or not such a component is actually implemented as an object.

Published Sunday, January 07, 2007 12:25 PM by andykr

No comments:

Post a Comment

Writing better code (Part 1)

Writing better code (Part 1) As we all know, Visual FoxPro provides an extremely rich and varied development environment but sometimes to...