The idea itself is sound. But it won't work, if you make the root type (here: NumberSet
) package private. Either expose that type or use a public interface instead. The actual implementation types should (and can) be hidden.
public abstract class NumberSet {
// Constructor is package private, so no new classes can be derived from
// this guy outside of its package.
NumberSet() {
}
}
public class Factories {
public NumberSet range(int start, int length) {
return new RangeNumberSet(start, length);
}
// ...
}
class RangeNumberSet extends NumberSet {
// ... must be defined in the same package as NumberSet
// Is "invisible" to client code
}
Edit To expose a hidden/private root type from a public API is a mistake. Consider the following scenario:
package example;
class Bar {
public void doSomething() {
// ...
}
}
public class Foo {
public Bar newBar() {
return new Bar();
}
}
and consider a client application using this API. What can the client do? It cannot properly declare a variable to have type Bar
since that type is invisible to any class outside of the package example
. It cannot even call public
methods on a Bar
instance it got from somewhere, since it does not know, that such a public method exists (it cannot see the class, let alone any members it exposes). So, the best a client can do here is something like:
Object bar = foo.newBar();
which is essentially useless. A different thing would be to have a public interface (or abstract class) instead of the package private one, as in the code defined above. In this case, the client actually can declare a variable of type NumberSet
. It cannot create its own instances or derive subclasses, since the constructor is hidden from it, but it can access the public API defined.
Edit again Even if you want a "featureless" value (from the client's perspective), i.e., a value, which does not define any interesting APIs the client may want to call, it is still a good idea to expose a public base type in the way described above. And be it only for the purpose of the compiler being able to perform type checking and allowing client code to temporarily store such a value into a (properly declared) variable.
If you don't want your client to call any API methods on the type: that's fine. There is nothing preventing you from not providing a public API on your (otherwise) public base type. Just don't declare any. Use an "empty" abstract base class (empty from the perspective of the client, since all interesting methods would be package private and thus hidden). But you have to supply a public base type nonetheless, or you should use plain Object
as return value, but then you forfeit error checking at compile time.
Rule of thumb: If the client has to call some method in order to obtain a value and pass it on to some other API, then the client actually knows, that there are some magic special values. And it has to be able to handle it in some way ("pass it on", at very least). Not providing a proper type for the client to deal with the values does not buy you anything except for (entirely appropriate) compiler warnings.
public abstract class Specification {
Specification() {
// Package private, thus not accessible to the client
// No subclassing possible
}
Stuff getInternalValue1() {
// Package private, thus not accessible to the client
// Client cannot call this
}
}
The above class is "empty" as far as the client code is concerned; it does not offer an usable API except stuff, which the Object
already offers. The major benefit of having it: the client can declare variables of this type, and the compiler is able to type check. Your framework, though, remains the only place, where concrete instances of this type can be created, and thus, your framework has total control over all values.