If we use the factory method we'll have to return created implementation as the type of an implemented interface.
public class Factory {
public Product getProduct() {
return new ProductA();
}
}
public interface Product {
}
class ProductA implements Product {
}
To avoid client's ability to cast returned Product to concrete implementation of the Product{A, B, C... etc.} we have to:
com.example.client
and com.example.factory
) package com.example.client;
...
public class Client {
public static void main(String[] args) {
Product i = new Factory().getProduct();
ProductA a = (ProductA) i; // the type of ProductA isn't visible.
}
}
For example we need to use the same factory with the hidden method
public class Factory {
public Product getProduct() {
return new ProductA();
}
Product[] getCreatedProducts() {
...
}
}
I see two problems here:
Default. When we don't use any keyword explicitly, Java will set a default access to a given class, method or property. The default access modifier is also called package-private, which means that all members are visible within the same package but aren't accessible from other packages: package com.
You specify that a method definition in an interface is a default method with the default keyword at the beginning of the method signature. All method declarations in an interface, including default methods, are implicitly public , so you can omit the public modifier.
By default, the variables and methods of a class are accessible to members of the class itself and to other classes in the same package.
The default scope is package-private. All classes in the same package can access the method/field/class. Package-private is stricter than protected and public scopes, but more permissive than private scope.
The "default" access does not guarantee much of anything, since any rogue programmer can declare their class in your package. Also, regardless of your package structure, in java, you almost always can do an "instance of" check, and then downcast to the "instance of" type. So, if your goal is to prevent any downcasting whatsoever, you must use the private
keyword. For example, you can declare the concrete implementations of your Product
interface as private static
or as anonymous inner classes within your Factory
. Indeed, in Bloch's "How to design a good API" article, he makes a point that you should "Minimize Accessibility of Everything."
That said, I think you're being a little paranoid here. Does it really matter that much to you if somebody downcasts? Any code that you write can be misused, and certainly if you include a well-documented factory then you have provided clear information about how to use your API properly. Also, if you build a real factory method that takes arguments and has clear method names, as opposed to this toy Factory
example that takes no arguments, then I think you'll find that you're broadcasting the publicly relevant part of what's being created anyway.
I do not really understand why do you want to put factory and classes to separate packages.
I usually create public interface, public factory class and package protected implementations in the same package. So client can create instances using factory only and cannot down cast because the concrete classes are not visible from other package.
In your case here, you have the client knows the factory which knows the implementation class. If they are all in the same process, then both the client and the implementation class are loaded into the same process, which means that the client can have access to the underlying methods of the implementation class via reflection. This assumes that you do not have complete control over the client runtime, i.e. taking measures to prevent reflection. However, if you did, then you probably wouldn't need to worry about the inability of the client to cast to the implementation class.
So, if you view this as a potential security mechanism against an untrusted client process, then I wouldn't put any faith in it. If you have control over the client, then this is probably good enough to keep errant programmers from making an unintentional mess.
I do not see the advantage of two packages. I suggest this alternative:
package com.example.client ;
public interface Product
{
/* stuff */
}
package com.example.client ;
public interface ProductFactory
{
Product make ( X1 x1 , X2 x2 , /* parameters */ , Xn xn ) ;
}
package com.example.manager;
interface ManagedProduct extends com.example.client.Product
{
/* management methods */
}
package com.example.manager ;
public final class DefaultProductFactory implements com.example.client.ProductFactory
{
public static final DefaultProductFactory instance = new DefaultProductFactory ( ) ;
private DefaultProductFactory ( )
{
super ( ) ;
}
public ManagedProduct make ( final X1 x1 , final X2 x2 , /* parameters */ , final Xn xn )
{
return new ManagedProduct ( )
{
/* implementation logic here */
} ;
}
/*
possibly other methods
The Product implementation class is invisible.
*/
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With