Sunday, 15 March 2015

Item 1: Consider static factory insted of constructor

Technique that should be part of Every Programmer Tool kit is static factory method.


Example :
public static Boolean valueOf(boolean b) {    return b ? Boolean.TRUE : Boolean.FALSE;}

It explains all the andproscons for both of them in the best way you can understand.

Just to quote the advantages and disadvantages from the book: -
Advantages: -
1. One advantage of static factory methods is that, unlike constructors, they have names.

2. The second advantage of static factory methods is that, unlike constructors, they are not required to create a new object each time they’re invoked. (instance-controlled.)

3. A third advantage of static factory methods is that, unlike constructors, they can return an object of any subtype of their return type.
Hiding implementation classes in this fashion leads to a very compact API.
Prior to Java 8, interfaces couldn’t have static methods. By convention, static factory methods for an interface named Type were put in a noninstantiable companion class (Item 4) named Types
As of Java 8, the restriction that interfaces cannot contain static methods was eliminated. it may still be necessary to put the bulk of the implementation code behind these static methods in a separate package-private class. This is because Java 8 requires all static members of an interface to be public
Java 9 allows private static methods, but static fields and static member classes are still required to be public.
4. A fourth advantage of static factory methods is that they reduce the verbosity of creating parameterized type instances (This one can be ignored in Java 7)
The EnumSet class (Item 36) has no public constructors, only static factories. 
if it has sixty-four or fewer elements, as most enum types do, the static factories return a RegularEnumSet instance, which is backed by a single long
if the enum type has sixty-five or more elements, the factories return a JumboEnumSet instance, backed by a long array

5.A fifth advantage of static factories is that the class of the returned object need not exist when the class containing the method is written.
Such flexible static factory methods form the basis of service provider frameworks like the Java Database Connectivity API (JDBC)
There are three essential components in a service provider framework:
service interface, which represents an implementation; 
provider registration API, which providers use to register implementations; 
and service access API, which clients use to obtain instances of the service. 
An optional fourth component of a service provider framework is service provider interface, which describes a factory object that produce instances of the service interface

In the case of JDBC, Connection plays the part of the service Interface, DriverManager.registerDriver is the provider registration APIDriverManager.getConnection is the service access API,
 and Driver is the service provider interface.

Disadvantages: -
1.The main limitation of providing only static factory methods is that classes without public or protected constructors cannot be subclassed. 
Arguably this can be a blessing in disguise because it encourages programmers to use composition instead of inheritance (Item 18), and is required for immutable types (Item 17)
2.A second shortcoming of static factory methods is that they are hard for programmers to find.
Here are some common names for static factory methods. 
• from—A type-conversion method that takes a single parameter and returns a corresponding instance of this type, for example:
Date d = Date.from(instant);
• of—An aggregation method that takes multiple parameters and returns an instance of this type that incorporates them, for example:
Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
• valueOf—A more verbose alternative to from and of, for example:
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
• instance or getInstance—Returns an instance that is described by its parameters (if any) but cannot be said to have the same value, for example:
StackWalker luke = StackWalker.getInstance(options);

• create or newInstance—Like instance or getInstance, except that the method guarantees that each call returns a new instance, for example:
Object newArray = Array.newInstance(classObject, arrayLen);
• getType—Like getInstance, but used if the factory method is in a different class. Type is the type of object returned by the factory method, for example:
FileStore fs = Files.getFileStore(path);
• newType—Like newInstance, but used if the factory method is in a different class. Type is the type of object returned by the factory method, for example:
BufferedReader br = Files.newBufferedReader(path);
• type—A concise alternative to getType and newType, for example:
List<Complaint> litany = Collections.list(legacyLitany);
To cite a real world example, a hammer is great at driving nails, adequate for jacking open a sealed crate with the nail-removing end (a crowbar would still be much better), but useless for planing down a rough surface.
Factory methods refer to one of a set of creational design patterns, i.e. paradigms for creating objects. In some creational design patterns such as "Builder" and "Prototype", the use of the new operator for object creation isn't merely discouraged, it's considered harmful to the overall design goal. The creational design patterns that people talk about are...
  1. Factory methods
  2. Abstract factory methods
  3. Singleton pattern
  4. Builder
  5. Prototype
Generally speaking, a factory method is used to create an object from a group of related subclasses based on data that the user or designer supplies to the method. More concretely, though, a static factory method gives you control over object creation even when the object that is returned is the same every time. This can be very important when, for example, the process of creating an object is very expensive in terms of time and resources. In a situation like this, using a new operator to create objects might incur a terrible performance penalty.
One solution might be to maintain a reusable pool of objects. By using a static factory method, the application designer can provide logic to return a free, existing object if one is available. This would then save the potentially high cost of building a new object. This is exactly what is done with network database connections by connection managers that provide "connection pooling." Rather than build a new database connection every single time a client makes a request, connection objects are assigned from a pool of existing objects if one is available. This is an example of a circumstance in which using the new operator would actually be harmful to application performance and would undermine the software engineer's design goals.
A good time to consider using a factory method for creating objects rather than the new operator would be:
  • The object that would be created is belongs to one of a few possible subclasses of objects that could be created depending on supplied data.
  • There is a good reason to have more control over the object creation process than would be possible in a constructor, eg. the Singleton design pattern requires a static factory method.
A bad time to consider using a factory method would be:
  • Simple, lightweight objects
It's all about enumerating the software design problems, and then deciding which tools are best for solving it. Static factory methods are good for some things and not so good for others ... just like any tool.
public interface Service {
// Service-specific methods go here
}

public interface Provider {
Service newService();
}



import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Services {
private Services() {
} // Prevents instantiation (Item 4)

// Maps service names to services
private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
public static final String DEFAULT_PROVIDER_NAME = "<def>";

// Provider registration API
public static void registerDefaultProvider(Provider p) {
registerProvider(DEFAULT_PROVIDER_NAME, p);
}

public static void registerProvider(String name, Provider p) {
providers.put(name, p);
}

// Service access API
public static Service newInstance() {
return newInstance(DEFAULT_PROVIDER_NAME);
}

public static Service newInstance(String name) {
Provider p = providers.get(name);
if (p == null)
throw new IllegalArgumentException(
"No provider registered with name: " + name);
return p.newService();
}
}


public class Test {
public static void main(String[] args) {
// Providers would execute these lines
Services.registerDefaultProvider(DEFAULT_PROVIDER);
Services.registerProvider("comp", COMP_PROVIDER);
Services.registerProvider("armed", ARMED_PROVIDER);

// Clients would execute these lines
Service s1 = Services.newInstance();
Service s2 = Services.newInstance("comp");
Service s3 = Services.newInstance("armed");
System.out.printf("%s, %s, %s%n", s1, s2, s3);
}

private static Provider DEFAULT_PROVIDER = new Provider() {
public Service newService() {
return new Service() {
@Override
public String toString() {
return "Default service";
}
};
}
};

private static Provider COMP_PROVIDER = new Provider() {
public Service newService() {
return new Service() {
@Override
public String toString() {
return "Complementary service";
}
};
}
};

private static Provider ARMED_PROVIDER = new Provider() {
public Service newService() {
return new Service() {
@Override
public String toString() {
return "Armed service";
}
};
}
};
}