2010-12-03 98 views
2

在我的项目jOOQ中,我使用复杂的数据结构对SQL查询建模。查询的所有组件执行如何不公开Java中的公共接口

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(); 
} 

这是唯一公开暴露的接口。实际查询部分的一个例子是:

public interface Table extends QueryPartProvider {} 
class TableImpl implements QueryPart, Table {} 

正如你所看到的,QueryPart方法只能通过Table.getQueryPart().toSQLDeclaration()访问等

我的设计有利于QueryPart方法劝阻直接访问,但不能完全把它藏起来。我的问题是:任何人都可以告诉我一个好的设计模式来实现这个目标吗?

注意:最简单但不是很好的解决方案是将所有对象转换为QueryPart,例如, ((QueryPart) table).toSQLDeclaration()

+2

为什么添加'getQueryPart'方法如果你想隐藏它? – Arne 2010-12-03 08:35:02

+0

您可以尝试隐藏实现此接口的对象。这是你需要的吗? – 2010-12-03 08:42:35

+0

@Arne:我想从客户端代码中隐藏它,但将它暴露给库。 @Stas:实现接口的对象是包私有的(参见TableImpl)。这些对象通过接口公开(参见表格) – 2010-12-03 08:46:18

回答

2

执行了类似sfussenegger的建议后,我想出了一个更好的解决方案,其中涉及适配器设计模式。这是总纲:

/** 
* Objects providing an internal API implement this interface 
*/ 
public interface Adapter { 

    /** 
    * Dynamically expose an (publicly unknown) internal API. 
    */ 
    <T> T internalAPI(Class<T> internalType) throws ClassCastException; 
} 

这种适配器类型是向公众公开任何内部事件的唯一事实。只有包私有实现方法知道该方法的可能参数(以及那些真正想要实际使用内部API的黑客,以获得解决方法,扩展等)。

/** 
* This type contains the public API for a QueryPart 
*/ 
public interface QueryPart extends Adapter { 
// [...] 
} 

/** 
* This type contains the internal API for a QueryPart 
*/ 
public interface QueryPartInternal extends QueryPart { 
// [...] 
} 

上面的QueryPart和QueryPartInternal是相关的。这个事实被公众所知,但没有public class/type扩展QueryPartInternal。只有以下包私人类和它的gazillion子类:

/** 
* This class is the base class for all QueryParts. 
* It is package private and thus doesn't expose anything 
*/ 
abstract class AbstractQueryPart implements QueryPartInternal { 
    // [...] 

    /** 
    * For other package private implementation methods 
    */ 
    @Override 
    public final <T> internalAPI(Class<T> internalType) { 
    return internalType.cast(this); 
    } 

    /** 
    * Convenience method for subclasses heavily using the 
    * internal API 
    */ 
    protected final QueryPartInternal internal(QueryPart part) { 
    return part.internalAPI(QueryPartInternal.class); 
    } 
    // [...] 
} 
5

接口的所有方法都是公开的,因此您无法访问图书馆客户端无法访问的内容。 也许你可以使用抽象类TablegetQueryPart()作为包保护方法来实现你想要的。我不确定我是否想这样做,而不是从TableTableImpl

1

你能解释一下你为什么想这样做吗?我可以看到的唯一原因是无法为库的用户实现接口。

我不认为这是一个好方法。只需添加一些Javadoc并解释为什么它没有意义实现它。但最后,请将其留给用户是否有正当的理由来创建自定义实现。预见每一个用例总是很困难。

如果坚持他的做法也肯定不是你的错有人全球有机纺织品标准 - 他不能说他没有被警告过:)

举一个例子,那就是你可以找到全国各地的Apache Wicket的源代码:

/** 
* THIS IS WICKET INTERNAL ONLY. DO NOT USE IT. 
* 
* Traverses all behaviors and calls ... 
*/ 

编辑: 只是另一种虽然:你可以试试这个,但我还是会鼓励它 - 不要说你没有得到警告;)

public interface ExposedInterface { 
    void foo(); 
} 

// only default visibility 
interface InternalInterface extends ExposedInterface { 
    // nothing here 
} 

// and here some methods 
ExposedInterface get(); // user can use it 

void set(InternalInterface obj); // user is out of luck here