简体   繁体   中英

What are static factory methods?

什么是“静态工厂”方法?

NOTE! "The static factory method<\/strong> is NOT<\/strong> the same as the Factory Method<\/strong> pattern" (c) Effective Java, Joshua Bloch.

(c) Effective Java, Joshua Bloch. Usually this method is inside a particular class.

The decision of object to be created is like in Abstract Factory made outside the method (in common case, but not always). While the key (!) idea of Factory Method is to delegate decision of what instance of class to create inside Factory Method. Eg classic Singleton implementation is a special case of static factory method. Example of commonly used static factory methods:

  • <\/li>
  • <\/li>
  • <\/li><\/ul>"

We avoid providing direct access to database connections because they're resource intensive. So we use a static factory method getDbConnection<\/code> that creates a connection if we're below the limit. Otherwise, it tries to provide a "spare" connection, failing with an exception if there are none.

public class DbConnection{
   private static final int MAX_CONNS = 100;
   private static int totalConnections = 0;

   private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();

   private DbConnection(){
     // ...
     totalConnections++;
   }

   public static DbConnection getDbConnection(){

     if(totalConnections < MAX_CONNS){
       return new DbConnection();

     }else if(availableConnections.size() > 0){
         DbConnection dbc = availableConnections.iterator().next();
         availableConnections.remove(dbc);
         return dbc;

     }else {
         throw new NoDbConnections();
     }
   }

   public static void returnDbConnection(DbConnection dbc){
     availableConnections.add(dbc);
     //...
   }
}

Readability can be improved by static factory methods:

Compare

public class Foo{
  public Foo(boolean withBar){
    //...
  }
}

//...

// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.

to

public class Foo{
  public static Foo createWithBar(){
    //...
  }

  public static Foo createWithoutBar(){
    //...
  }
}

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();

It all boils down to maintainability. The best way to put this is whenever you use the new<\/code> keyword to create an object, you're coupling the code that you're writing to an implementation.

When you create all of your objects using constructors, you are essentially hard-wiring the code that uses the object to that implementation. The code that uses your object is "dependent on" that object. This may not seem like a big deal on the surface, but when the object changes (think of changing the signature of the constructor, or subclassing the object) you have to go back and rewire things everywhere.

Dependency Injection is basically equivalent to factories but allows you to specify how your objects get wired together declaratively (through configuration or annotations).

If the constructor of a class is private then you cannot create an object for class from outside of it.

class Test{
 int x, y;
 private Test(){
  .......
  .......
  }
}

I thought i will add some light to this post on what i know. We used this technique extensively in our recent android project . Instead of creating objects using new operator you can also use static method to instantiate a class. Code listing:

//instantiating a class using constructor
Vinoth vin = new Vinoth(); 

//instantiating the class using static method
Class Vinoth{
  private Vinoth(){
  }
  // factory method to instantiate the class
  public static Vinoth getInstance(){
    if(someCondition)
        return new Vinoth();
  }
}

Static methods support conditional object creation : Each time you invoke a constructor an object will get created but you might not want that. suppose you want to check some condition only then you want to create a new object.You would not be creating a new instance of Vinoth each time, unless your condition is satisfied.

Another example taken from Effective Java .

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

This method translates a boolean primitive value into a Boolean object reference. The Boolean.valueOf(boolean) method illustrates us, it never creates an object. The ability of static factory methods to return the same object from repeated invocations allows classes to maintain strict control over what instances exist at any time.

Static factory methods is that, unlike constructors , they can return an object of any subtype of their return type. One application of this flexibility is that an API can return objects without making their classes public. Hiding implementation classes in this fashion leads to a very compact API.

Calendar.getInstance() is a great example for the above, It creates depending on the locale a BuddhistCalendar , JapaneseImperialCalendar or by default one Georgian .

Another example which i could think is Singleton pattern , where you make your constructors private create an own getInstance method where you make sure, that there is always just one instance available.

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}

One of the advantages that stems from Static factory is that that API can return objects without making their classes public. This lead to very compact API. In java this is achieved by Collections class which hides around 32 classes which makes it collection API very compact.

A factory method a method that abstracts away the instantiation of an object. Generally factories are useful when you know that you need a new instance of a class that implements some interface but you don't know the implementing class.

You could simply hard-code calls to the constructors for concrete implementations of each widget but if you ever wanted to swap one toolkit for another you'd have a lot of places to change. By using a factory you reduce the amount of code you would need to change.

One of the advantages of the static factory methods with private constructor(object creation must have been restricted for external classes to ensure instances are not created externally) is that you can create instance-controlled<\/em> classes. And instance-controlled classes guarantee that no two equal distinct instances exist( a.equals(b) if and only if a==b<\/strong> ) during your program is running that means you can check equality of objects with ==<\/strong> operator instead of equals<\/strong> method, according to Effective java.

Classes that do this are said to be instance-controlled. There are several reasons to write instance-controlled classes. Instance control allows a class to guarantee that it is a singleton (Item 3) or noninstantiable (Item 4). Also, it allows an immutable class (Item 15) to make the guarantee that no two equal instances exist: a.equals(b) if and only if a==b. If a class makes this guarantee, then its clients can use the == operator instead of the equals(Object) method, which may result in improved performance. Enum types (Item 30) provide this guarantee.

Java implementation contains utilities classes java.util.Arrays and java.util.Collections both of them contains static factory methods , examples of it and how to use :

Also java.lang.String class have such static factory methods :

  • String.format(...), String.valueOf(..), String.copyValueOf(...)

A static factory method is good when you want to ensure that only one single instance is going to return the concrete class to be used.

For example, in a database connection class, you may want to have only one class create the database connection, so that if you decide to switch from Mysql to Oracle you can just change the logic in one class, and the rest of the application will use the new connection.

If you want to implement database pooling, then that would also be done without affecting the rest of the application.

It protects the rest of the application from changes that you may make to the factory, which is the purpose.

The reason for it to be static is if you want to keep track of some limited resource (number of socket connections or file handles) then this class can keep track of how many have been passed out and returned, so you don't exhaust the limited resource.

static

<\/blockquote>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM