OK, here's why I think we should drop the 'm'.
Hmmmm ....OK...let me back up....
An object should conform to a contract. Once the object is created,
that contract has been signed, sealed and delivered. At least, that is
the intention. However, Java often falls down on this. We have
"Init" methods. We have Property setters that must be called before we
have a "valid" object.
Why? Java is a pretty strongly typed language. But, it needs to be
able to interface with scripting languages, and thus it has, among
other things, the reflection API. Reflection has the ability to
enumerate the properties (member variables) of the object, and to fetch
values from the object without having to have a compile time
dependency. We can even make variables that are Read Only by tagging
them as 'final'.
A final field must be defined by the time the constructor has returned.
The dependencies to decide the value for the final field must be passed
in to the constructror.
The constructor is available via reflection. the Parameters are
avialable via reflection...but....
Not the names of the parameters. This is possibly the largest oversight
in the Java language. Without named parameters, a scripting language
cannot do anything to determine which of the values it has maps to which
of the dependencies of the constructor. All it can do is try to pass
them in the right order.
So what happened?
Java has a nasty covention called the bean API. A naming convention
get<CapitalizedName> and set<CapitalizedName>. Want to make somethig
read only, drop the set.
Joshua Blcok sets out an important rule of thumb in Effective Java:
Favor Immutable Objects. An immutable object is implicitly thread
safe. The Bean API with its late initialzation of properties makes
this impossible.
However, we have hope. In recent versions of Java, the Attribute API
makes it possible to automatically build classes that let us create a
Dictionary to pass to the constructor based on the names of the
parameters. There is also the possibility of getting named parameters
into the Java standard in the future.
Regardless, this is only really an issue for scripting languages. Our
application is all Java. This means that we can use classes and type
safety to strongly associate the dependecies of a constructor with the
objects that can fulfil those dependencies. We don't need to play
"Everything is a string" like Javascript does.
We can have immutable objects, without the bean API. And we can expose
the properties of those objects as final properties instead of
get<CapitalizedName>. But this only makes sense if the names of the
properties are the "good name".
This has the potential to make code that is much more readable and
concise, while increasing type safety.
Yes, increasing type safety. If a string field is immutable, but it
needs some business logic, say to confirm that it complies with a
pattern, we create a class that encapsulated that format, and make an
immutable instance of that class. The pattern is confirmed in the
constructor. If we try to make an instance that does not conform,
throw an exception.
Here is how it is done in a beanAPI way:
public class Certificate{
String fingerprint;
String getFingerprint(){
return fingerprint;
}
String setFingerprint(String fingerprint)
throws IllegalArgumentException
{
validateFingerprint(fingerprint);
this.fingerprint = fingerprint;
}
}
Note that the logic for fingerprint is encapsulated in the Certificate
object, and cannot be cleanly separated out.
Here's the refactored solution.
public class Fingerprint{
private String internal;
public Fingerprint(String) throws InvalidArgumentException{
...
}
String toString(){
...
}
}
public class Certificate{
public final Fingerprint fingerprint;
puiblic Certificate (Fingerprint fingerprint) {
this.fingerprint = fingerprint;
}
}