- 13. Minimize the accessibility of classes and members
- 14. In public classes, use accessor methods, not public fields
- 15. Minimize mutability
- 16. Favor composition over inheritance
- 17. Design and document for inheritance or else prohibit it
- 18. Interface is better than Abstract class
- 19. Interface for defining type only
- 20. Prefer class hierarchies to tagged classes
- 21. Function object as strategies
- 22. Favor static member classes over nonstatic
13. Minimize the accessibility of classes and members
Four accessibilities in Java:
- private: only accessible inside the class itself
- package-private(default): accessible inside the package
- protected: accessible from subclasses of the class where it is declared, and from any class inside the package
- public: accessible from anywhere
It is not acceptable to make a class, interface or member a part of a package's exported API to facilitate testing.
Instance fields should never be public. if the field is not
final, and it is public, that means you give up the control to limit the ability to store in this field. Also, classes with public mutable fields are not thread-safe.
For static field, it is ok if it declares to be
final. The naming convention for these field is upper case.
A nonzero-length array is always mutable, so it is wrong for a class to have a public static final array field, or an accessor that returns such a field. The elements inside the array can be modified. You can make a the public array private and add a public immutable list. Or return a clone of that private array
14. In public classes, use accessor methods, not public fields
The reason to do it is flexibility: easy to change to way to get and set the value, without affecting other parts of the code
However, if a class is package-private or is a private nested class, there is nothing inherently wrong with exposing its data fields.
15. Minimize mutability
Some advices to make things immutable:
- Don't provide any methods that modify the object's state(aka. mutators)
- Ensure that the class can't be extended
- Make all fields final
- Make all fields private
- Ensure exclusive access to any mutable components. If your class has any fields that refer to mutable objects, ensure that clients of the class cannot obtain references to these objects.
Immutable objects can be shared freely, they require no synchronization.
The only disadvantage of immutable classes is that they require a seperate object for each distinct value. Use lazy initialization.
To ensure the immutability, a class must not permit itself to be suclassed. Static factory is a good way to implement it instead of constructor.
No methods may produce an externally visible change in the object's state.
Example: Complex number
16. Favor composition over inheritance
Unlike method invocation, inheritance violates encapsulation. If superclass changes implementation, subclass will be affected.
If every A object has a B object inside, the class A is called wrapper class. This is the Decorator design pattern. This is not delegation, unless wrapper passes itself to the wrapped object.
17. Design and document for inheritance or else prohibit it
If design for inheritance, the class must document its self-use of overridable methods. For every public or protected methods, the documentation must indicate which overridable methods the method or constructor invokes
18. Interface is better than Abstract class
Abstract class limits a class more than interface.
Interface is an ideal option for mixin definition of class.
Skeleton Implementation(Abstract interface), makes it easy to provide implementation for interface. It combines the advantage of both interface and abstract class.
Simulated Multiple Inheritance: makes a private internal class implements an interface, so that the public class can implements multiple abstract class if needed.
Example: Skeleton Implementation
Skeleton implementation is designed for inheritance. The methods that don't have a concrete implementation can have a simple implementation, like
setValue() in the example.
Once a interface is published and widely adopted, it is almost impossible to change it.
19. Interface for defining type only
Constant interface: contains no methods, only static final fields. It is for defining constants. IT IS NOT A GOOD WAY TO USE INTERFACE. An example is
java.io.ObjectStreamConstants. It is a bad example from Java API.
Better implementation is Utility class.
20. Prefer class hierarchies to tagged classes
Tagged class: many seperated implementation dumped into one class. Tagged class is always too long, low performance.
Subclass is better than tagged class. Tagged class is a simulation of class hierarchies.
21. Function object as strategies
This is Strategy design pattern.
StringLengthComparator is stateless, no fields, therefore it is better to be implemented as a singleton.
If we have many comparators, we'd better define a comparator interface. (Actually it is inside
It is also recommended to have a static strategy factory class, the concrete strategy implementation classes are inside the factory class, and they all implement the strategy interface.
22. Favor static member classes over nonstatic
Nested class is internal class, for serving the enclosing class. There are four types of nested class: static member class, nonstatic member class, anonymouse class and local class.
Static member class is just normal class that defined inside a class, no special purpose. It is an accesory of enclosing class.
Nonstatic member class is much different than static member class. The instance of nonstatic member class may related to an enclosing instance. They may call the method of enclosing class.
Example: nonstatic member class
MyIterator class, if it is not required to visit enclosing class, then it may be declared as
Anonymous class has no class name, cannot execute
instanceof test. It is suitable for dynamicly create function object. or create process object like
Local class is just other local class.