Showing posts with label interface methods. Show all posts
Showing posts with label interface methods. Show all posts

Thursday, October 11, 2012

Method scope

I want to talk in this blog about an aspect of Java that is often paid little attention: method scope.  My way of doing things might not be 100% mainstream, but I believe it makes good sense.

If your class extends a super-class, then you obviously will not be able to reduce the scope of any methods.  Should you widen the scope of any super-methods?  Probably not.

What about non-overridden methods?  If the method is defined by an interface, then it must be declared public -- end of story.  But should any other methods be public?  Well, let's think about how methods in our class will get invoked.  One mechanism of invocation is via reflection, in particular, introspection.  Introspection looks for public methods with names of the form:
  • boolean isX() and its mate setX(boolean);
  • T getX() and its mate setX(T).
These are known as "bean" methods, or property descriptor setters/getters.  Any such method can be invoked by reflection, in particular by inversion-of-control-container (dependency injection) type configuration.  So, if you want these properties to be settable by reflection, you need to declare them public.  There's only one snag with this mechanism: Java doesn't provide any way to mark these bean methods as discoverable (and invokable)  via reflection.  You just have to "know." In practice, there may also be other reflection-invokable methods such as void addX(T) or void putX(String,T).

If you have these reflectible methods or other non-overridden methods that you want to be invoked from other classes by the normal calling mechanism, then you need to declare them public and, if the method receiver type will normally be an interface, then they must go in the interface.

What this implies is that, for a class that will normally be referenced via its interface (thus appropriately hiding the specifics of any concrete class), the only public methods in that class will be the bean methods and the interface methods.  No other method needs to be declared public because there will be no way to invoke it.

Meanwhile, what about protected and default scope?  I tend to use protected scope only for methods that are used internally (that's to say they are invoked by a base class) and declared either abstract or with a trivial default behavior and which are expected to be overridden by concrete classes to define class behavior. Occasionally, I will define a concrete non-overridable method as protected when I am sure that I only want it to be invoked by sub-classes.  And, typically, the only need for default scope is when you create an inner class within a class and you want to create a method which will allow communication between an inner class and its outer class.

Everything else should be declared private.  I like to use long names for private methods which thus give a good description of what the private method does (naturally, it only does one thing!).  I do not create javadoc annotation for private method or fields because I typically filter out all private objects from the resulting javadoc.

I also feel that private methods should not normally handle any exceptions.  Exceptions should be handled at a level where handling is either required or opportune.  Therefore, private methods may have a long list of thrown exceptions, as required.

And while good practice suggests keeping short parameter lists for public methods, private methods can use as many parameters as they please.

Finally, a word on the other method modifiers, apart from scope.  Marking individual methods as final is unusual, but is necessary in certain cases, for example delegated callback methods.  And what about the distinction between class methods (static) and instance methods?  I have the Java compiler configured to warn me about methods which can be defined as static, but aren't.  This is very useful and something which I have long looked for.  I feel that declaring a method as an instance method when it really should be a class method is just plain wrong because it implies a dependence on this when none exists.

OK, back to work!

Monday, February 28, 2011

Things that Java got wrong, part 2: interface method bodies

The concept of the interface in Java is undoubtedly one of the best things about the language.  It almost, but not quite, makes up for not having pure multiple inheritance.  I particularly like the fact that you can define zero or more method signatures as well as zero or more constants.

But why not allow abstract method bodies?  If that sounds like a contradiction in terms, let me try to explain.  I'm using the term abstract in the sense of non-concrete.  Let's take an example.  You define an interface called SetOperable<T> and you define the following methods:

public abstract SetOperable<T> intersect(SetOperable<T> s);

 public abstract SetOperable<T> union(SetOperable<T> s);

 public abstract Collection<T> members();

 public abstract SetOperable<T> clear();

 public abstract SetOperable<T> add(T t);
Now, whereas you want to be able to implement the set operations on any type T, you are clearly going to have to define, in a concrete type, either the intersect or the union method.  But the other method is normally derivable in terms of the first.

So, in Java, you must create an abstract class which implements the required interface and which looks something like the following:

public abstract class SetOperable_<T> implements SetOperable<T> {

 @Override
 public SetOperable<T> union(final SetOperable<T> s) {
  final Collection<T> temp = new ArrayList<T>(members());
  temp.addAll(s.members());
  final SetOperable<T> intersection = intersect(s);
  final SetOperable<T> result = intersection.clear();
  final Collection<T> duplicates = intersection.members();
  final Iterator<T> iterator = temp.iterator();
  while (iterator.hasNext()) {
   final T t = iterator.next();
   if (duplicates.contains(t)) {
    iterator.remove();
    duplicates.remove(t);
   }
  }
  for (final T t : temp)
   result.add(t);
  return result;
 }
}

Concrete classes will extend this abstract class, defining the details of intersect, members, clear, add, etc.  But it would be so much nicer to be able to define this union method in the interface itself and not have to bother with an abstract class, assuming of course that you can define the method in terms of the interface (or its super-interfaces).  Scala allows you to do just that, at least in its own way, but not Java.

I admit that it's not the end of the world, but it can be awkward if you have a concrete class that should extend some other type as well as extending the above abstract class.  You can't have it extend both.  In the given example, you might want your concrete class to extend AbstractSet, for example.

OK, back to work!