srh
srh

Reputation: 1661

Is it really an Adaptor pattern?

On a project I have seen some code which was written by a former employee. The person has named it as an implementation of Adaptor pattern but I am not sure. Here is the code:

public class RowSetAdaptor implements java.io.Serializable {
    private javax.sql.rowset.CachedRowSet cachedRowSet;

    public RowSetAdaptor() throw SQLException {
        cachedRowSet = new com.sun.rowset.CachedRowSetImpl();
    }

    public void populate(ResultSet resultSet) throw SQLException {
        cachedRowSet.populate(resultSet);
    }

    public boolean next() throw SQLException {
        cachedRowSet.next();
    }
    
    .... // different methods all using cachedRowSet
} 

The way I see it the class RowSetAdaptor is restricting access to CachedRowSet interface as not all methods of CachedRowSet interface are available in RowSetAdaptor class. Is it really an Adaptor pattern? If not then which design pattern is being used here?

Update [Feb 24, 2015]

Thanks @JB Nizet , @Fuhrmanator , @Günther Franke , @vikingsteve and @Giovanni Botta for your answers.

What if I make following modifications to make it an Adapter pattern?

public interface RowSetI {
    public boolean next() throws SQLException;
    ...
}

public class CachedRowSetAdapter implements RowSetI {
    private javax.sql.rowset.CachedRowSet cachedRowSet;

    public CachedRowSetAdapter() throw SQLException {
        cachedRowSet = new com.sun.rowset.CachedRowSetImpl();
    }

    public void populate(ResultSet resultSet) throw SQLException {
        cachedRowSet.populate(resultSet);
    }

    public boolean next() throw SQLException {
        cachedRowSet.next();
    }
    ...
}

public class JdbcRowSetAdapter implements RowSetI {
    private javax.sql.rowset.JdbcRowSet jdbcRowSet;

    public JdbcRowSetAdapter() throw SQLException {
        jdbcRowSet = new com.sun.rowset.JdbcRowSetImpl();
    }

    public void populate(ResultSet resultSet) throw SQLException {
        jdbcRowSet.populate(resultSet);
    }

    public boolean next() throw SQLException {
        jdbcRowSet.next();
    }
    ...
}

TIA

Upvotes: 3

Views: 766

Answers (4)

Fuhrmanator
Fuhrmanator

Reputation: 12882

The best way to see if something's an implementation of a pattern is to map the roles/methods in the GoF definition to the implementation.

GoF Adapter has two variants (class and object adapter) which have different structures. Class adapters use multiple inheritance:

Class adapter

You have a class RowSetAdaptor, which would make it a candidate for the Adapter class in this diagram. However, RowSetAdaptor implements only Serializable, so I thinking it can't be this form of the Adapter pattern.

The second variant is the object adapter:

Object Adapter

Again, RowSetAdaptor would be the Adapter class in this diagram. It does appear that javax.sql.rowset.CachedRowSet would be the adaptee, since it's using that class inside of some of its methods. However, the purest GoF Adapter must implement some Target interface and probably wrap an object Adaptee in its constructor (CachedRowSet is hard-coded). Some might say Serializable is the Target interface, but that would imply it would adapt those request() methods. RowSetAdaptor doesn't override anything in Serializable that I can see.

Finally, if it's really the GoF Adapter pattern, I'd expect there to be more than one Adapter. Generally, Target interface is designed because there is some common functionality that is implemented by different adapters (it makes little sense to have an interface with only one implementation).

Another noteworthy point is that Client shouldn't know it's using a RowSetAdaptor; Client only sees an object of the Target type. It's hard to justify using an interface with a client if the client is just going to access the implementation directly.

Perhaps you can check the code for the Client class or other adapters.

My conclusion is that based on the code you presented, it's not a convincing example of GoF Adapter pattern.

See more real examples of adapters at https://stackoverflow.com/a/13323703/1168342

Upvotes: 1

vikingsteve
vikingsteve

Reputation: 40378

Yes, it is still the Adapter pattern.

An adapter enables two incompatible interfaces to work together.

From the java world, we are used to seeing Adapters (e.g. MouseAdapter and MouseListener) that are not actually adapters in the true sense (so please be aware of that).

In your example however, the adapter seems to have the intention to reduce the size and complexity of the interface of CachedRowSet into a new interface named RowSetAdapter that is also Serializable.

The fact that the example uses composition rather than inheritance does not exclude it from being an Adapter pattern, I think it is a good Adapter example in fact, although you could also argue it also represents the Proxy pattern.

Upvotes: 1

GFranke
GFranke

Reputation: 237

If the class RowSetAdaptor adapts the CachedRowSet interface in any way then RowSetAdaptor can be seen as an implementation of the Adapter design pattern (object adapter).

But in your example listing I can't see any adaptation - operations are simply forwarded to the cachedRowSet object - so that clients can access the CachedRowSet interface directly.

RowSetAdaptor introduces an additional level of indirection, which complicates design and costs performance. It should only be used if clients can't or shouldn't access the CachedRowSet interface directly.

"A design pattern should only be applied when the flexibility it affords is actually needed."
[GoF book, page 31]

Note: The Adapter design pattern (object adapter) suggests that clients refer to an interface (Target) to make them independent of a concrete implementation class (Adapter).
In your example, clients refer to (and depend on) the concrete RowSetAdaptor class.

For further discussion see the GoF Design Patterns Memory / Adapter design pattern at http://w3sdesign.com.

Upvotes: 2

Giovanni Botta
Giovanni Botta

Reputation: 9816

Well the class does implement Serializable (it relies on the fact that CachedRowSetImpl is Serializable), so technically it is an adapter. The reason why this is necessary can be found here.

As far as whether this is a good idea or not, that's a whole other can of worms (the result set can be huge, it would make more sense to serialize using a different format, e.g., json, protobuf, etc.).

Upvotes: 0

Related Questions