Hum, interface design

I love interfaces, but most of what I've learned is from trial and error.
I would recommend Joshua Bloch's
Effective Java book for general programming practices many of which are related to interfaces.
Online, maybe start with general design principles like:
http://en.wikipedia.org/wiki/Dependency_inversion_principlehttp://en.wikipedia.org/wiki/Coupling_%28computer_programming%29http://en.wikipedia.org/wiki/Cohesion_%28computer_science%29For example, it's a very helpful that
InputStream and
DataInput are interfaces that do not require extending and can be implemented by any class.
However, it's also very helpful that there are default implementations for these interfaces such as
FileInputStream,
ObjectInputStream, and
ByteArrayInputStream.
It's important to balance a package, module, or API with both interfaces and default implementations (commonly preceded by the word Abstract in the Java libraries). For example:
ListModel has an
abstract and
default implementation, making it much more useful.
Whereas something like
TimerTask is more annoying to use since it must be extended. In my opinion, TimerTask could have been a concrete class with a constructor that took a Runnable object and ran that object instead of forcing every class that ever wanted to use TimerTask to extend it.
Common interface designs that I use are the builder pattern (
http://javarevisited.blogspot.com/2012/06/builder-design-pattern-in-java-example.html)
which is something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class Thing { private int id; private Element matter;
public Thing(int id, Element matter) { this.id = id; this.matter = matter; }
public void thingStuff() { } }
public class ThingBuilder implements Builder<Thing> { private int thingId; private Element thingMatter;
public void setId(int id) { this.thingId = id; }
public void setElement(Element matter) { this.thingMatter = matter; }
@Override public Thing create() { return new Thing(thingId, thingMatter); } }
public interface Builder<T> { public T create(); } |
and the service pattern (couldn't find many good web examples, here's a general discussion about it:
http://www.velocityreviews.com/forums/t302202-service-provider-pattern.html)
and it looks something like this in its most basic form:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public interface XyzService { }
public interface XyzProvider { public XyzService newXyzService(); }
public class Services { private static final Map<String, XyzProvider> providers = new ConcurrentHashMap<String, XyzProvider>();
public static void registerProvider(String name, XyzProvider p) { providers.put(name, p); }
public static XyzService newInstance(String name) { XyzProvider p = providers.get(name); if(p == null) { throw new IllegalArgumentException("No provider registered with the name '" + name + "'"); } return p.newXyzService(); } } |
-Adapted from
Effective Design Item 1.
For example, in java.util.concurrent
Executor serves the role of XyzService in our example and
Executors fulfills the role of Services in our example.
Good interface design is normally about abstracting away details, such as hiding a database connection so that it could easily be replaced with a file or hiding LWJGL's rendering system so that you can easily modify it for better performance or update it when a new version of LWJGL comes out.