Friday, September 4, 2009

Patterns - 024: Structural patterns ( adapter )


In general, clients of a class access the services offered by the class through its interface. Sometimes, an existing class may provide the functionality required by a client, but its interface may not be what the client expects.

In such cases, the existing interface needs to be converted into another interface, which the client expects.

This can be accomplished by using the Adapter pattern. The Adapter pattern suggests defining a wrapper class around the object with the incompatible interface. This wrapper object is referred as an adapter and the object it wraps is referred to as an adaptee. The adapter provides the required interface expected by the client.


Class Adapter


A class adapter is designed by subclassing the adaptee class. In addition, a class adapter implements the interface expected by the client object. When a client object invokes a class adapter method, the adapter internally calls an adaptee method that it inherited.


Object Adapter

An object adapter contains a reference to an adaptee object. Similar to a class adapter, an object adapter also implements the interface, which the client expects. When a client object calls an object adapter method, the object adapter invokes an appropriate method on the adaptee instance whose reference it contains.

Class Adapters Object Adapters

Based on the concept of inheritance.

Uses object composition.

Can be used to adapt the interface ofthe adaptee only. Cannot adapt theinterfaces of its subclasses, as theadapter is statically linked with theadaptee when it is created.

Can be used to adapt the interface of theadaptee and all of its subclasses.

Because the adapter is designed as asubclass of the adaptee, it is possibleto override some of the adaptee’sbehavior.
Note: In Java, a subclass cannot override amethod that is declared as final in itsparent class.

Cannot override adaptee methods.
Note: Literally, cannot “override” simplybecause there is no inheritance. Butwrapper functions provided by theadapter can change the behavior as required.

The client will have some knowledge of the adatee’s interface as the full public interface of the adaptee is visible to the client.

The client and the adaptee are completely decoupled. Only the adapter is aware of the adaptee’s interface.

In Java applications:
Suitable when the expected interface is available in the form of a Java interface and not as an abstract or concrete class. This is because the Java programming language allows only single inheritance. Since a class adapter is designed as a subclass of the adaptee class, it will not be able to subclass the interface class (representing the expected interface) also, if the expected interface is available in the form of an abstract or concrete
class.

In Java applications:
Suitable even when the interface that a client object expects is available in the form of an abstract class. Can also be used if the expected interface is available in the form of a Java interface.
Or
When there is a need to adapt the interface of the adaptee and also all of its subclasses.

In Java applications:
Can adapt methods with protected access specifier.

In Java applications:
Cannot adapt methods with protected access specifier, unless the adapter and the adaptee are designed to be part of the same package.


Example

Let us build an application to validate a given customer address. This application can be part of a larger customer data management application.

The application already has a Customer object which validate the USAddress that implements the AddressValidator interface by calling the isValidAddress() method.



       public interface AddressValidator {
           public boolean isValidAddress(String inp_address,
                                         String inp_zip, String inp_state);
       }

Let us say that the application needs to be enhanced to deal with customers from Canada as well.

Let us assume that a utility class CAAddress, with the required functionality to validate a given Canadian address, already exists.

But The CAAddress class offers an isValidCanadianAddr method, but the Customer expects an isValidAddress method as declared in the AddressValidator interface. This incompatibility in the interface makes it difficult for a Customer object to use the existing CAAddress class.

Changing the CAAddress class interface can affect all of those current clients of the CAAddress class.


Class Adaptor


Applying the Adapter pattern, a class adapter CAAddressAdapter can be designed as a subclass of the CAAddress class implementing the AddressValidator interface.


Because the adapter CAAddressAdapter implements the AddressValidator interface, client objects can access the adapter CAAddressAdapter objects without any problems. When a client object invokes the isValidAddress method on the adapter instance, the adapter internally translates it into a call to the inherited isValidCanadianAddr method.







          public class CAAddressAdapter extends CAAddress
                          implements AddressValidator {

              public boolean isValidAddress(String inp_address,
                              String inp_zip, String inp_state) {

                  return isValidCanadianAddr(inp_address, inp_zip,
                          inp_state);
              }
          }
      


Object Adaptor


Now let us assume that the client expects the AddressValidator interface to be available as an abstract class instead of a Java interface. Because the adapter CAAdapter has to provide the interface declared by the AddressValidator abstract class, the adapter needs to be designed to subclass the AddressValidator abstract class and implement its abstract methods. Because multiple inheritance is not supported in Java, now the adapter CAAddressAdapter cannot subclass the existing CAAddress class as it has already used its only chance to subclass from another class.

Applying the object Adapter pattern, the CAAddressAdapter can be designed to contain an instance of the adaptee CAAddress . This adaptee instance is passed to the adapter by its clients, when the adapter is first created. In general, the adaptee instance contained by an object adapter may be provided in the following two ways:

  • Clients of the object adapter may pass the adaptee instance to the adapter. This approach is more flexible in choosing the class to adapt from, but then the client may become aware of the adaptee or the fact of adaptation. It is more suitable when the adapter needs any specific state from the adaptee object besides its behavior.
  • The adapter may create the adaptee instance on its own. This approach is relatively less flexible and suitable when the adapter does not need any specific state from the adaptee, but needs only its behavior.


            public abstract class AddressValidator {
              public abstract boolean isValidAddress(String inp_address,
                  String inp_zip, String inp_state);
            }


            class CAAddressAdapter extends AddressValidator {

              private CAAddress objCAAddress;

              public CAAddressAdapter(CAAddress address) {
                objCAAddress = address;
              }
              public boolean isValidAddress(String inp_address,
                  String inp_zip, String inp_state) {

                return objCAAddress.isValidCanadianAddr(inp_address,
                       inp_zip, inp_state);
              }
            }
            



No comments:

Post a Comment