Does "implementation" below mean instance of an object? Perhaps they mean the implementing code.
Consider adding static interface methods, to allow the client code to create (potentially specialized) objects that implement the interface. For example, if we have an interface Point with two methods int x() and int y(), then we can expose a static method Point.of(int x, int y) that produces a (hidden) implementation of the interface.
So, if x and y are both zero, we can return a special implementation class PointOrigoImpl (with no x or y fields), or else we return another class PointImpl that holds the given x and y values. Ensure that the implementation classes are in another package that are clearly not a part of the API (e.g. put the Point interface in com.company. product.shape and the implementations in com.company.product.internal.shape).
Do This:
Point point = Point.of(1,2);
Don't Do This:
Point point = new PointImpl(1,2);
The advantage being that this enforces encapsulation? However, if the implementation is package private and not part of the API, would that not create access problems? If the client, "world" as here:
https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
doesn't have access to the implementation of Point
then how can it possibly instantiate a new Point
as above for "do this"?
For example, if we have an interface Point with two methods int x() and int y(), then we can expose a static method Point.of(int x, int y) that produces a (hidden) implementation of the interface.
1) Be aware, since Java 8 you can add a static method in an interface, but before you cannot.
2) I have some difficulties to understand this advise :
So, if x and y are both zero, we can return a special implementation class PointOrigoImpl (with no x or y fields), or else we return another class PointImpl that holds the given x and y values. Ensure that the implementation classes are in another package that are clearly not a part of the API (e.g. put the Point interface in com.company. product.shape and the implementations in com.company.product.internal.shape).
Here is an example Point
class that matches to the text you refer to:
package com.company.product.shape;
import com.company.product.internal.shape.PointOrigoImpl;
import com.company.product.internal.shape.PointImpl;
public interface Point{
int x();
int y();
static Point of(int x, int y) {
if (x == 0 && y == 0){
return new PointOrigoImpl();
}
return new PointImpl(x, y);
}
}
If the Point
interface is provided to clients and that it declares the factory method, to compile fine, the Point
interface has to necessarily have the visibility to PointOrigoImpl
and PointImpl
classes in order to instantiate them.
As the Point
interface and the subclasses are in two distinct packages (com.company.product.shape
and com.company.product.internal.shape
),
that means that PointImpl
and PointOrigoImpl
should have a public constructor otherwise Point
could not instantiate them.
Finally, clients who manipulate Points may also instantiate the constructor of PointImpl
and PointOrigoImpl
subclasses.
It defeats the purpose of a factory that doesn't want to expose the implementation to choose itself the implementation to return.
An interface is public and is designed to be fully accessible to the client.
So as a general rule it should not contain implementations that we don't want to expose to clients.
3) Here :
The advantage being that this enforces encapsulation? However, if the implementation is package private and not part of the API, would that not create access problems? If the client, "world" as here: doesn't have access to the implementation of Point then how can it possibly instantiate a new Point as above for "do this"?
I suppose you wonder why the text says : Ensure that the implementation classes are in another package that are clearly not a part of the API.
In the text you refer to, the author wants to let the interface be known by Point
clients but he doesn't want to subclasses of Point
be known because he wants to decide the Point subclass to return according to the parameter used in the factory Point.
Point clients will know only this interface.
In Java, in order to not providing the access to implementation classes you can use public class, interface and inner private class :
With the example you refer to, it would be straight.
Point (interface) :
public interface Point{
int x();
int y();
}
Point factory (public class that contains private classes) :
public final class PointFactory {
// private classes
private class PointImpl implements Point {
private int x;
private int y;
private PointImpl(int x, int y) {
this.x = x;
this.y = y;
}
public int x() {
return x;
}
public int y() {
return y;
}
}
private class PointOrigoImpl implements Point {
public int x() {
return 0;
}
public int y() {
return 0;
}
}
// end private classes
public Point of(int x, int y) {
if (x == 0 && y == 0) {
return new PointOrigoImpl();
}
return new PointImpl(x, y);
}
}