如何在 Java 中不公开公共接口
在我的项目 jOOQ 中,我使用复杂的数据结构对 SQL 查询进行建模。查询的所有组件都实现
public interface QueryPart {
int bind(java.sql.PreparedStatement stmt);
int bind(java.sql.PreparedStatement stmt, int initialIndex);
SQLDialect getDialect();
String toSQLDeclaration();
String toSQLDeclaration(boolean inlineParameters);
String toSQLReference();
String toSQLReference(boolean inlineParameters);
}
该接口的方法,由库的所有包在内部使用来构造和执行 SQL。不应直接从客户端代码调用它们。为此,我添加了
public interface QueryPartProvider {
QueryPart getQueryPart();
}
Which is the only publicly expose 接口。实际查询部分的一个示例是:
public interface Table extends QueryPartProvider {}
class TableImpl implements QueryPart, Table {}
如您所见,QueryPart 方法只能通过 Table.getQueryPart().toSQLDeclaration() 等访问。
我的设计有助于阻止直接访问 QueryPart 方法,但无法完全隐藏。我的问题是:谁能告诉我一个好的设计模式来实现这个目标?
注意:最简单但不是很好的解决方案是将所有对象转换为 QueryPart,例如 ((QueryPart)表).toSQLDeclaration()
In my project jOOQ, I model SQL queries with a complex data structure. All components of a query implement
public interface QueryPart {
int bind(java.sql.PreparedStatement stmt);
int bind(java.sql.PreparedStatement stmt, int initialIndex);
SQLDialect getDialect();
String toSQLDeclaration();
String toSQLDeclaration(boolean inlineParameters);
String toSQLReference();
String toSQLReference(boolean inlineParameters);
}
This interface's methods are used internally by all packages of the library to construct and execute SQL. They should not be invoked directly from client code. For that purpose, I have added
public interface QueryPartProvider {
QueryPart getQueryPart();
}
Which is the only publicly exposed interface. An example of an actual query part is:
public interface Table extends QueryPartProvider {}
class TableImpl implements QueryPart, Table {}
As you can see, the QueryPart methods can only be accessed via Table.getQueryPart().toSQLDeclaration()
, etc.
My design helps discouraging direct access to QueryPart methods, but cannot completely hide it. My question is: Can anyone tell me a good design pattern to achieve this goal?
Note: The simplest but not very nice solution would be to cast all objects to QueryPart, e.g. ((QueryPart) table).toSQLDeclaration()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
接口的所有方法始终是公共的,因此您无法访问库客户端也无法访问的内容。
也许您可以使用
Table
的抽象类和受包保护的getQueryPart()
方法来实现您想要的目的。但我不确定我是否想要这样做,而不是从Table
到TableImpl
的转换。All methods of an interface are always public, so there is no way for you to have access to something which is not accessible to your library clients as well.
Maybe you could achieve what you want using an abstract class for
Table
, and thegetQueryPart()
method as package protected. I'm not sure however that I would want to do that, instead of a cast fromTable
toTableImpl
.在实现了与 sfussenegger 建议类似的方法后,我想出了一个更好的解决方案,涉及适配器设计模式。这是总体概要:
此适配器类型是向公众公开的有关任何内部内容的唯一事实。只有包私有实现方法知道此方法的可能参数(以及那些真正想要实际使用内部 API 来解决方法、扩展等的黑客)。
上面的QueryPart和QueryPartInternal是相关的。这一事实为公众所知,但没有公共类/类型扩展 QueryPartInternal。只有以下包私有类及其无数子类可以:
After implementing something similar to what sfussenegger suggested, I came up with an even better solution involving the Adapter design pattern. This is the general outline:
This adapter type is the only fact exposed to the public about anything internal. Only package private implementation methods know about the possible arguments to this method (and those hackers that really want to actually use the internal API for workarounds, extensions, etc).
The above QueryPart and QueryPartInternal are related. This fact is known to public but no public class / type extends QueryPartInternal. Only the following package-private class and its gazillion subclasses do:
您能解释一下为什么您想这样做吗?我能看到的唯一原因是使您的库的用户无法实现该界面。
我认为这不是一个好方法。只需添加一些 Javadoc 并解释为什么实现它没有意义。但最后,让用户决定是否有正当理由创建自定义实现。预见每一个用例总是很困难。
如果有人坚持他的方法,那肯定不是你的错 - 他不能说他没有被警告:)
举个例子,这就是你可以在 Apache Wicket 的源代码中找到的内容:
编辑:
只是另一个:你可以尝试这个,尽管我仍然不鼓励它 - 不要说你没有被警告过;)
Could you please explain why you'd like to do that? The only reason I can see is to make it impossible to implement the interface for a user of your library.
I don't think that's a good approach. Simply add some Javadoc and explain why it doesn't make sense to implement it. But finally, leave it to the user whether there's a valid reason to create a custom implementation. It's always difficult to foresee each and every use case.
If somebody gots stuck with his approach it's certainly not your fault - he can't say he hasn't been warned :)
To give an example, that's what you can find all over Apache Wicket's source code:
EDIT:
just another though: you could try this, although I'd still discourage it - don't say you haven't been warned ;)