Supposing I have an interface Foo and a given implementation FooImpl.
public class FooImpl implements Foo
If I want to define a new operation on this class that depends on the particular implementation, is it correct to define it in the implementation class or as a static method on an Util class like FooUtils.operation?
public class FooImpl {
public void operation() {
...
}
}
public class FooUtils {
public static void operation(Foo f) {
...
}
}
The first option forces me to cast to the given implementation class whenever I want to use it on an object that is declared of the type of the interface (it is good practice to program against interfaces). For example:
Foo f = FooImpl.newInstance();
((FooImpl) f).operation();
which is a bit ugly.
The second option doesn't have this problem but it is not very pretty either:
FooUtils.operation(f)
-
related (possibly a duplicate): Design for an interface implementation that provides additional functionalitygnat– gnat2014年11月12日 14:16:15 +00:00Commented Nov 12, 2014 at 14:16
-
In a nuttshell, variable f should be declared as FooImpl if you need to call operation(). You can pass f to methods which operate on Foo, but methods that operate on Foo shouldn't cast a Foo to anything, so shouldn't call operation().Andrew Hoffman– Andrew Hoffman2014年11月12日 15:14:48 +00:00Commented Nov 12, 2014 at 15:14
2 Answers 2
If not every implementer of Foo
is supposed to contain operation()
, then operation()
cannot be declared in Foo
, plain and simple.
Programming against interfaces rather than concrete classes is a good idea, but only if the interface actually is sufficient for your needs. If you need to call operation()
, then you should declare FooImpl
, or maybe a custom subinterface of Foo
, but never Foo
. That would completely subvert the point of using an interface: not having to know concrete subclasses.
-
It's worth mentioning that you can define methods on the interface and as long as you implement them there you don't have to implement them at every implementor (at least in Java 8).Benjamin Gruenbaum– Benjamin Gruenbaum2014年11月12日 19:29:31 +00:00Commented Nov 12, 2014 at 19:29
-
@BenjaminGruenbaum In fact, Java only supports that from Java 8 onwards and it has some limitations. For example, you are very limited in what the
default
implementation can access.blalasaadri– blalasaadri2014年11月13日 01:16:00 +00:00Commented Nov 13, 2014 at 1:16
First, if you find yourself always doing casting before calling some operation, it might be a sign that there's something wrong with your inheritance structure. If your inheritance is good, all the methods can be called by other classes are exposed in the interface and you will not need to do casting
Not everything needs to be abstracted in the interface. You will generally use interface for testability (to introduce fake object easily) or if you have several implementation. I'll not use interface for domain entities.
Whether to put operation in the class or in another class, need to see the nature of the operation. Does the operation use most of the fields from this class? If so most probably it belongs to this class. For me, generally I'll try to avoid static method, unless it's really something not related to domain logic