public interface IntSet2 {
public IntSet2 add(int i);
public boolean contains(int i);
}
Notes
final public class IntSet2s {
private static IntSet2 append(final int i, final IntSet2 set) {
return new IntSet2() {
public IntSet2 add(int i) {
return append(i, this);
}
public boolean contains(int j) {
return i == j || set.contains(j);
}
};
}
public IntSet2 singleItemIntSet(final int i) {
return new IntSet2() {
public IntSet2 add(int i) {
return append(i, this);
}
public boolean contains(int j) {
return i == j;
}
};
}
public IntSet2 evenIntSet() {
return new IntSet2() {
public IntSet2 add(int i) {
return append(i, this);
}
public boolean contains(int i) {
return i % 2 == 0;
}
};
}
public IntSet2 emptyIntSet() {
return new IntSet2(){
public IntSet2 add(int i) {
return singleItemIntSet(i);
}
public boolean contains(int i) {
return false;
}
};
}
}
- All the objects created in this program are anonymous instances of the IntSet2 interface. Any code that want to can implement this interface!
- We have completely side-stepped classes. We use constructor functions to create instances of IntSet2.
- Code cannot use an instanceof test to tell which implementation of the IntSet2 is being used. In fact, it has no way of telling the difference between the different implementations other than by observing their behavior through the interface.
- Each implementation of interface can have a completely different representation, and it is impossible, even for instances of the same interface, to see the representation of an IntSet2.
- Benefits: Programming to interfaces can give great flexibility by allowing any piece of code to implement it, so long as the implementation conforms to the documented behavior.
- Caveats: It can sometimes be hard to implement efficient code in some cases where this pure object style is used.