3

在一个项目中,我看到了一些由前雇员编写的代码。该人已将其命名为适配器模式的实现,但我不确定。这是代码:

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
} 

我看到它的方式RowSetAdaptor是限制对CachedRowSet接口的访问,因为并非所有CachedRowSet接口方法都在RowSetAdaptor类中可用。它真的是适配器模式吗?如果不是,那么这里使用的是哪种设计模式?

更新 [2015 年 2 月 24 日]

感谢@JB Nizet、@Fuhrmanator、@Günther Franke、@vikingsteve 和@Giovanni Botta 的回答。

如果我进行以下修改以使其成为适配器模式怎么办?

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

4

4 回答 4

2

如果类以任何方式RowSetAdaptor适应接口,则可以将其视为适配器设计模式(对象适配器)的实现。CachedRowSetRowSetAdaptor

但是在您的示例清单中,我看不到任何适应 - 操作只是转发到cachedRowSet对象 - 以便客户端可以 CachedRowSet直接访问接口。

RowSetAdaptor引入了额外的间接级别,这使设计和成本性能变得复杂。只有当客户端不能或不应该CachedRowSet直接访问接口时才应该使用它。

“只有在实际需要它所提供的灵活性时,才应该应用设计模式。”
[GoF 书,第 31 页]

注意:适配器设计模式(对象适配器)建议客户端引用接口(目标)以使它们独立于具体的实现类(适配器)。
在您的示例中,客户端引用(并依赖于)具体RowSetAdaptor类。

如需进一步讨论,请参阅http://w3sdesign.com上的 GoF 设计模式内存/适配器设计模式。

于 2015-02-03T12:22:31.657 回答
1

是的,它仍然是适配器模式。

适配器使两个不兼容的接口能够一起工作。

在 Java 世界中,我们习惯于看到Adapters(例如MouseAdapterMouseListener)实际上不是真正意义上的适配器(所以请注意这一点)。

但是,在您的示例中,适配器似乎有意将接口的大小和复杂性减小为CachedRowSet名为RowSetAdapterthat is also的新接口Serializable

该示例使用组合而不是继承这一事实并不排除它成为一种Adapter模式,我认为它实际上是一个很好的Adapter例子,尽管您也可以说它也代表了Proxy模式。

于 2015-02-02T17:37:07.680 回答
1

查看某事物是否是模式实现的最佳方法是将 GoF 定义中的角色/方法映射到实现。

GoF 适配器有两个变体(类和对象适配器),它们具有不同的结构。类适配器使用多重继承:

类适配器

您有一个 class RowSetAdaptor,这将使它成为Adapter此图中该类的候选者。但是,RowSetAdaptorimplements only Serializable,所以我认为它不可能是适配器模式的这种形式。

第二个变体是对象适配器:

对象适配器

同样,RowSetAdaptor将是Adapter此图中的类。看起来确实javax.sql.rowset.CachedRowSet是被适配者,因为它在它的一些方法中使用了那个类。但是,最纯粹的 GoF 适配器必须实现一些Target接口,并且可能Adaptee在其构造函数中包装一个对象(CachedRowSet是硬编码的)。有人可能会说SerializableTarget接口,但这意味着它将适应这些request()方法。RowSetAdaptor不会覆盖Serializable我可以看到的任何内容。

最后,如果它真的是 GoF 适配器模式,我希望会有不止一个适配器。一般来说,Target接口的设计是因为有一些共同的功能由不同的适配器实现(只有一个实现的接口没有什么意义)。

另一个值得注意的点是不Client应该知道它使用的是RowSetAdaptor; Client只看到该Target类型的对象。如果客户端只是要直接访问实现,那么很难证明使用客户端的接口是合理的。

也许您可以检查 Client 类或其他适配器的代码。

我的结论是,根据您提供的代码,这不是 GoF 适配器模式的令人信服的示例。

在https://stackoverflow.com/a/13323703/1168342查看更多真实的适配器示例

于 2015-02-05T15:49:57.863 回答
0

那么这个类确实实现了(它依赖于isSerializable的事实),所以从技术上讲它是一个适配器。之所以需要这样做,请参见此处CachedRowSetImplSerializable

至于这是否是一个好主意,那完全是另一回事(结果集可能很大,使用不同的格式进行序列化会更有意义,例如 json、protobuf 等)。

于 2015-02-02T17:35:27.220 回答