This item is applicable to all object orientated languages, not just to Java. Encapsulation and abstraction are both well understood and I do not believe there is a lot to argue with in general.
The item explains that classes should not contain public instance fields and should instead use private instance fields, getters and, in the case of mutable classes, setters. The advantage being that you can change the classes implementation without having to change its interface. All standard stuff.
There are, however, two things worth discussing. Bloch suggests that it may be acceptable to make immutable (final) instance fields public and instance fields within classes that are package-private or private-nested public.
Paul Grenyer
Saturday, 27 December 2008
Friday, 19 December 2008
Item13: Minimize the accessibility of classes and members
This is the first item in the Chapter about Classes and Interfaces. It deals with the first of the fundamental principles of object oriented design: information hiding or encapsulation. This concept is already well known and described in Parnas famous ACM article. All OO languages have support for that, so does Java.
Reasons for information hiding should be obvious:
6.6) (private, package private, protected, public) for classes, interfaces and members (methods and attributes). The rule of thumb is simple:
make the artefacts as inaccessible as possible (so make them private if possible).
In Java you have two options: For classes and interfaces you can have package-private and and public. For members (fields, methods, nested classes and nested interfaces) you can have private, package-private, protected, public. The default (if you write nothing) is always package-private.
Note: In Effective C++ Scott Meyers as the same rule (3rd edition, Item 22). The interesting thing Scott discusses there: protected is not better than public (at least for C++, because there is no final clause to prohibit inheritance)
Usually a good API design, should use as much private as possible gain
the Parnas properties we described above. However caveat: I you implement Serializable, also private and package-private fields, leak into the public API,
which is not what the designer/programmer intended (Item 74/75 describe this in more detail).
Note also: that even private and package-private members are accessible via reflection from arbitrary classes. So if a programmer intends to violate the information hiding rules, he CAN do this in java via some reflection tricks.
Note that a similar problem is also there in C++, e.g. if you pass out the pointer to a private member via a public method, you loose all the encapsulation guaranteed of the language.
Josh continues discussing rules about backward compatibility and some minor issues with "trying to change the access level".
A good collection about backward compatibility rules I found really really useful is that of eclipse. (URL below).
It is really worth reading this rule collection: !
http://wiki.eclipse.org/index.php/Evolving_Java-based_APIs
http://wiki.eclipse.org/Evolving_Java-based_APIs_2
http://wiki.eclipse.org/Evolving_Java-based_APIs_3
Of course, classes with public mutable fields are not thread-safe, so
watch out for this and avoid it like a plague. The only thing you should have are public static final fields, containing constants for this class, written in UPPER_CASE_NOTATION. Note however that these public static final fields should ONLY be primitive values or references to immutable objects. If you have a final field with a reference to a mutable object or a static final array field, you are lying at yourself. You might feed better in the first place but such fields are still mutable, what you really have is a serious security hole .
So the basic rules for me to remember are:
Reasons for information hiding should be obvious:
- it enables to decouple modules and hence the system can get a better
internal software quality
(in terms of developing, testing, understanding, maintaining, etc). - it also enables or increases software reuse
(though we should have a look at this, so that we do not copy and past
modules, etc).
6.6) (private, package private, protected, public) for classes, interfaces and members (methods and attributes). The rule of thumb is simple:
make the artefacts as inaccessible as possible (so make them private if possible).
In Java you have two options: For classes and interfaces you can have package-private and and public. For members (fields, methods, nested classes and nested interfaces) you can have private, package-private, protected, public. The default (if you write nothing) is always package-private.
Note: In Effective C++ Scott Meyers as the same rule (3rd edition, Item 22). The interesting thing Scott discusses there: protected is not better than public (at least for C++, because there is no final clause to prohibit inheritance)
Usually a good API design, should use as much private as possible gain
the Parnas properties we described above. However caveat: I you implement Serializable, also private and package-private fields, leak into the public API,
which is not what the designer/programmer intended (Item 74/75 describe this in more detail).
Note also: that even private and package-private members are accessible via reflection from arbitrary classes. So if a programmer intends to violate the information hiding rules, he CAN do this in java via some reflection tricks.
Note that a similar problem is also there in C++, e.g. if you pass out the pointer to a private member via a public method, you loose all the encapsulation guaranteed of the language.
Josh continues discussing rules about backward compatibility and some minor issues with "trying to change the access level".
A good collection about backward compatibility rules I found really really useful is that of eclipse. (URL below).
It is really worth reading this rule collection: !
http://wiki.eclipse.org/index.php/Evolving_Java-based_APIs
http://wiki.eclipse.org/Evolving_Java-based_APIs_2
http://wiki.eclipse.org/Evolving_Java-based_APIs_3
Of course, classes with public mutable fields are not thread-safe, so
watch out for this and avoid it like a plague. The only thing you should have are public static final fields, containing constants for this class, written in UPPER_CASE_NOTATION. Note however that these public static final fields should ONLY be primitive values or references to immutable objects. If you have a final field with a reference to a mutable object or a static final array field, you are lying at yourself. You might feed better in the first place but such fields are still mutable, what you really have is a serious security hole .
So the basic rules for me to remember are:
- Strive for the complete and minimal public API of a class/interface (Scott Meyers has the same rule...)
- Prevent any access from outside that is not necessary.
- ensure that public static final fields are REALLY immutable
- if API backward compatibility matters, obey the Eclipse Java based API Evolution rules (links are in this article)
Sunday, 7 December 2008
Item 12: Consider implementing Comparable
Consider implementing Comparable interface in your classes.
The sole method of
This is needed to interoperate with all the many generic algorithms and collection implementations that use it, like
The object compares with argument object, returns a negative integer if other object is smaller, zero if same and a positive integer if bigger. A
A ClassClass Exception is thrown if it can't be compared.
There are a few differences between
The item also talks about order of comparison. This is obvious to me. You must determine the significance of each field, or you might not get the order you expect. Good programming practice in any language.
For integer fields you could just subtract the two fields and return the value. However, if the difference is larger than the type allows (one field is a very large positive number and one is a very large negative number), and the result could overflow the type. This is a very hard bug to find. Another good programming tip in any language.
The sole method of
Comparable
interface is compareTo
. Used when instances have a natural ordering, especially value classes. Therefore this is not useful if you need to sort array of classes multiple different ways. It only allows one way to sort. Sorting is then easy with collections.Arrays.sort(a);
This is needed to interoperate with all the many generic algorithms and collection implementations that use it, like
TreeSet<>
The object compares with argument object, returns a negative integer if other object is smaller, zero if same and a positive integer if bigger. A
compareTo
method to match the contract must have reflexivity, symmetric and transitivity just like equals
. If they are not followed, it could break collector classes that depend on it. The compareTo
method could in theory compare different types of objects, unlike equals
but it is normally not done. I looked around to determine how, but not sure. I have not done much programming in Java, using this group to learn. Does anyone know if this is ever useful?A ClassClass Exception is thrown if it can't be compared.
There are a few differences between
compareTo
and equals
. Comparable
interface is templated and therefore staticly typed, the arguments do not need to be type checked or cast. Field comparisons are done by order not by equality. You must use compareTo
or an explicit Comparator. For primitive fields, use relational operators < and >. For floating point fields use Double.compare
or Float compare since the relational operators do not obey the general contract for these types.The item also talks about order of comparison. This is obvious to me. You must determine the significance of each field, or you might not get the order you expect. Good programming practice in any language.
For integer fields you could just subtract the two fields and return the value. However, if the difference is larger than the type allows (one field is a very large positive number and one is a very large negative number), and the result could overflow the type. This is a very hard bug to find. Another good programming tip in any language.
Subscribe to:
Posts (Atom)