3

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

Community
  • 1
  • 1
srh
  • 1,427
  • 3
  • 22
  • 45
  • 2
    It's not an adapter, as it doesn't adapt an interface to another interface. It's... not any pattern. – JB Nizet Feb 02 '15 at 17:21
  • the 2 answers below says it is an Adapter pattern. Can you give your input on why those 2 answers are not correct? – srh Feb 02 '15 at 18:07
  • IMO, vikingsteve's answer has a too broad interpretation of the adapter pattern. To me, the adapter pattern is the following: I need to call a method which take an interface A as argument with an instance of B that doesn't implement A. So I write a class that implements A by delegating to the object of type B. In that sense, if the goal is really to have a Serializable, you might argue that Giovanni's answer is correct. But I'm not sure that is the intention of the author. – JB Nizet Feb 02 '15 at 19:06
  • See some examples that *are* adapters [here](http://stackoverflow.com/questions/11079605/any-real-example-of-adapter-pattern) – Fuhrmanator Feb 05 '15 at 15:00
  • @JBNizet I don't think your definition goes far enough. It's just as easy to modify B to support A in your example (rather than create an adapter). The *true* GoF adapter is needed when you have *several* possible B's that you *can't* modify, so you wrap them with adapters to A. – Fuhrmanator Feb 05 '15 at 15:21

4 Answers4

2

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.

GFranke
  • 207
  • 2
  • 8
1

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.

vikingsteve
  • 34,284
  • 19
  • 101
  • 142
  • The GoF definition of adapter is not this broad. It's pretty specific. It uses subclasses of a fixed adapter API. For your MouseAdapter example, see http://stackoverflow.com/a/9244294/1168342 For the MouseListener, that's Observer pattern (e.g. `mouseReleased` would be the method called when the mouse [subject]'s button is released). – Fuhrmanator Feb 05 '15 at 15:08
  • Thanks, I'll try to find a reference the GoF adapter pattern to include. – vikingsteve Feb 05 '15 at 15:09
1

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

Community
  • 1
  • 1
Fuhrmanator
  • 7,907
  • 4
  • 51
  • 88
  • Thanks. Awesome answer. I am thinking that if I make some changes in the code, it can become an object adapter. The comments dont allow much formatting here so I will use the main question for my suggestive changes. Please give your input on those suggested changes. – srh Feb 24 '15 at 22:18
0

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.).

Community
  • 1
  • 1
Giovanni Botta
  • 8,996
  • 5
  • 45
  • 88
  • A true adapter would adapt some method of `Serializable` - what method is the Adapter adapting? Also, why do you cite a reason that has -1 total votes as a question? – Fuhrmanator Feb 05 '15 at 16:21
  • @Fuhrmanator the `Serializable` interface is a tagging interface. It tells the JVM that the object can be serialized over the wire. It does not add a public interface to any object but it does use an implicit interface that [must be declared private](http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html) in case of custom serialization. `ResultSet` is not `Serializable` and the reason was clearly explained in the _response_ to that question (upvoted 3 times), so this class "adapts" `ResultSet` to conform to the __implicit__ interface specified by `Serializable`. – Giovanni Botta Feb 05 '15 at 16:25
  • @Fuhrmanator by the way, we are getting into more of a semantic argument rather than a functional one. We do not know what the intent of the original author of the class was and how this class is being used, so the code looks pretty open to interpretation to me. `RowSetAdaptor` only implements one interface, so if we wanted to follow the canonical definition, I feel like that is the interface it adapts to. You could argue that `RowSetAdaptor` is itself an interface, although not in the java sense, and since it is also married to the implementation, it seems like a pretty useless adapter IMO. – Giovanni Botta Feb 05 '15 at 16:33