views:

561

answers:

7

I was reading Joshua Bloch's "Effective Java Programming Language Guide".
He explains static factory methods could be used to avoid unnecessary duplicate objects.
I haven't quite understood this.
Could anyone explain?

+4  A: 

When you invoke a constructor, it always will return a new object (unless an exception is thrown). Static factory methods, or any kind of factory for that matter, don't have to always return a new object. For example, the getInstance() method on the traditional Singleton design pattern is a factory method that always returns the exact same object. There are cases where sometimes you want to do this kind of thing, whether it is to enforce an object can only be instantiated once, or to create some kind of object pool, etc. In general, I think this is a fringe reason for using static factory methods. The main purpose is to create nicely-named pseudo-constructors.

Here's a (somewhat silly) example of using static factory methods to make nicely-named pseudo-constructors. Consider this class:

class Person {

   public Person(Role role) {
      setRole(role);
   }

   ...
}

Without static factory methods, you might do something like this:

Person employee = new Person(Role.EMPLOYEE);
Person manager = new Person(Role.MANAGER);

Instead you could create static factory methods:

class Person {

   public static Person newEmployee() {
      return new Person(Role.EMPLOYEE);
   }

   public static Person newManager() {
      return new Person(Role.MANAGER);
   }

   private Person(Role role) {
      setRole(role);
   }

   ...
}

and you might instead do something like this:

Person employee = Person.newEmployee();
Person manager = Person.newManager();

This may not be a good example, but consider a more complex constructor or one with a less descriptive parameter. Sometimes going the factory method route makes the code more clear. There are of course drawbacks...

As far as limiting object creation, consider some strange constraint like there can never be more than one CEO:

class Person {

   private static Person singletonCEO = new Person(Role.CEO);

   public static Person newCEO() {
      return singletonCEO;
   }

   ...
}

and how it would be created:

Person ceo1 = Person.newCEO();
Person ceo2 = Person.newCEO();

assertThat(ceo1, is(ceo2)); // JUnit 4.x

I hope these examples help.

SingleShot
Could you provide code snippet for a better understanding? Thanks!
Kevin Boyd
I have tried to :-)
SingleShot
+2  A: 

The factory method pattern can be useful for times when there is no need to create a new instance of an object in order to perform some action.

Here are a couple of general cases I can think of where a static factory method which returns the same object can come in handy:

  1. The object is expensive to create -- There is a lot of processing when the object is instantiated, so instantiating the object more than once is not desirable. (This is also related to the Singleton pattern.)

  2. The object keeps no state -- If there is no state difference between the instances, there is no good purpose to create a new object every time.

The Wikipedia page on the factory method pattern has more information on this topic.


Let's take a look at a concrete example.

The DateFormat class uses the getInstance static method to return a DateFormat instance, which can be used to format a Date into a preset formatting depending on the locale of the machine.

Since the DateFormat that is returned is using the same formatting for every date formatting action, there is no real reason for creating a new DateFormat instance every time.

In general, the way this is implemented is to create an instance if an instance does not already exist, and then keep a reference to that instance. If the instance is needed again, the reference is returned. (This is generally how the Singleton pattern is implemented as well.)

For example:

class MySingleInstanceObject {

  private MySingleInstanceObject instance;

  private MySingleInstanceObject() {
    // Initialize the object.
    // This may be expensive.
  }

  public MySingleInstanceObject getInstance() {
    if (instance == null) {
      instance = new MySingleInstanceObject();
    }

    return instance;
  }
}

(FYI, the above code is an example of a singleton. Also, it is not thread-safe.)

coobird
If the factory method is invoked multiple times, in what way does it ensure that only one object is returned? Does it hold a reference to the object and check it for null?
Kevin Boyd
Yes. There are code examples at the wiki for Singleton pattern: http://en.wikipedia.org/wiki/Singleton_pattern
jimyi
Note that you can get even more flexibility (plus testability) by using an IoC Container (dependency injection) framework and letting it control the lifetimes of objects.
TrueWill
A: 

If you have a factory class to create object instantiations, every time you go to create an object you will have to instantiate the factory class as well. Basically you would be creating duplications of this factory class.

If it is static, you only have the one instance of the factory to be used.

ghills
No, it's not about the factory, it's about the objects it creates.
Andrei Vajna II
A: 

I was able to read some of this book here. After reading what he wrote it seems that what he is saying is that static factory methods give you more flexibility as a developer and it also allows you to be more explicit with what is being returned. When you contrast this to a constructor the constructor may not provide clarity in terms of what is being returned. Additionally you can do things like caching etc in the static factory method which I thought was fascinating. This approach seems like a good approach if you need this level of control and flexibility.

The point on not creating unnecessary duplicate objects come in if you want to use caching. With this static factory approach you could return the same object on each call to the static factory method.

an example:

public class Person
{

   private Person(string firstName, string lastName)
   {
      this.FirstName = firstName;
      this.LastName = lastName;
   }

   public string FirstName {get; private set;}
   public string LastName {get; private set;}

   private static Dictionary<string, Person> objectPool = new Dictionary<string, Person>();
   private object lockObject = new object();

   public static Person CreatePerson(string firstName, string lastName)
   {
      var result = objectPool[firstName + lastName];
      Person person = null; 
      if (result != null)
      {
         return result
      }
      lock(lockObject)
      {
          person = new Person(firstName, lastName);
          objectPool.Add(firstName + lastName, person)
      }
      return person;
   }
}
Michael Mann
Well I could not understand the caching part either from the book, maybe I could ask that question later.
Kevin Boyd
Well... the caching is saving you the overhead of creating a new instance of something that you really do not want to. In that situation it would be ok to hand the caller back the same instance because state is not important. An example would be a service that you are using in your code. The service provides a function for you. You could save yourself the overhead of creating a new instance by handing the caller back the same object
Michael Mann
+5  A: 

All the answers on non-duplication seem to focus on the singleton pattern, which is a good example of non-duplication, but a bad pattern to use in the general case. In my view a given application should have zero to one singletons in it, with a preference for zero. However, that has little to do with not creating unneccesary objects.

Consider instead an application that has to make a lot of Date objects. It is making so many Date objects that the construction of the Date objects is having an adverse effect on performance. So instead calling the constructor of the Date object, the code is refactored to only create Dates through a factory method. Inside this factory method, a Map is checked to see if the date requested was already created. If it was, then the same object is returned from the Map. Otherwise a new one is created, put in the Map and returned.

What seems to be confusing you is how by calling the factory method you prevent creating a duplicate object. Just by calling a factory method doesn't really change anything. What calling the factory allows is for code to take over and make a decision about creating the object. When calling new, no such decisions can be made.

See also this question for some more insight into the pattern and what it can be used for.

Yishai
Quite a concise, to the point answer!
Kevin Boyd
Yeah, I think so, too. And good point about Singleton!
Andrei Vajna II
Date is a bad example because it is (through bad design) mutable, and it really shouldn't be a bottleneck (unless I've missed something).
Tom Hawtin - tackline
@Tom, true in the standard API. I was thinking of a JODA time.
Yishai
A very good example of this in the JDK is Integer and Long. If you use the valueOf static factory, the JDK can pre-create, say, numbers between -100 and 100 - and return the same object for those. Another example where this is quite handy is for cases where object construction is expensive (i.e. maybe it involves a read from a database). Using a cache and returning an object from cache can greatly improve performance in some cases (we use this technique in the jdbm embedded database).
Kevin Day
+2  A: 

One real-world example:

Java supports both primitive and object types to represent a byte. When you convert a primitive to object you could do something like:

Byte b = new Byte( (byte) 65);

Butt this would create a new instance for every call. Instead you do:

Byte b = Byte.valueOf( (byte) 65);

On every call, the method valueOf() will returns the same instance of a Byte object representing the byte value 65.

After 10000 calls the 1st example would have created 10000 objects, whereas the second only one, because Byte class has an internal cache of Byte objects representing all numbers between -128 and 127.

idrosid
A very good answer indeed!
Kevin Boyd
It will have created 256 through the initialisation of the "cache", or none if the cache was already initialised. There is not initialisation done on an instance basis.
Tom Hawtin - tackline
Indeed the initialisation of the cache will create 256 instances. This is because there is a static initialiser in the Byte class that pre-populates the cache. Obviously the developer thought that pre-populating the cache is more efficient that lazy initialisation. However this is not an important characteristic of the static factory method. It can be implemented either way.
idrosid
+2  A: 

If I remember well, he also gives an example in the book. Consider Decimal. Zero is quite often used. So if you would call the static factory method Decimal.valueOf("0")(don't know if this is the actual API, but that doesn't matter for the sake of this example) it will return you an instance of the Decimal reprezenting 0 and it would be the same instance for any call. The implementation would be something like this:

public class Decimal {
    private static Decimal zero = new Decimal(0);

    public static Decimal valueOf(String s) {
        if (s.equals("0")) {
            return zero;
        } else {
            return new Decimal(parse(s)); // or whatever
        }

    // rest of the class
}

Notice that there is only a single instance of zero, while for any other number a new object is created. Also, this works with factory methods, and you can't do this with constructors. That's what Bloch was trying to point out, as an advantage for the former.

And, as Yishai mentioned, it's not that tightly related to Singleton. As you can see, you can have plenty of Decimal objects around. Instead, you can use factory methods to have full control on the number of instances you create. That's why it's called a Factory.

Andrei Vajna II