静态工厂方法每次调用

时间:2015-04-22 12:02:21

标签: java static factory

在Effective Java中,它提到"与构造函数不同,静态工厂方法在每次调用时都不需要创建新对象"。

class Car{
     String color;
     Boolean spoiler;

     public Car(String s){
        color=s;
        spoiler = false;
     }

     public static Car redCar(){
        return new Car("red");
    }
  }

在大班:

    Car c2 = Car.redCar();
    Car c3 = Car.redCar();        

c2和c3是不同的对象。我没有得到"每次调用时都不需要创建新对象"。

8 个答案:

答案 0 :(得分:7)

因为你做的是:

public static Car redCar(){
    return new Car("red");
}
        //  ^ here

如果您想返回相同的值,可以执行以下操作:

private static final Car RED_CAR = new Car("red");

public static Car redCar(){
    return RED_CAR;
}

关键是调用new Car()总是返回一个新实例。调用Car.newInstance()表示Car类可以决定该做什么。

例如:

private static final Map<String, Car> CARS = new HashMap<>();

public static Car newInstance(final String colour){
    return CARS.computeIfAbsent(colour, Car::new);
}

这会将Car构造函数用作新method reference方法的Map.computeIfAbsent,如果Car中没有Map的颜色,则会调用它1}}。这是一个天真的(不是线程安全的)缓存实现。

所以:

final Car one = Car.newInstance("red");
final Car two = Car.newInstance("red");
System.out.println(one == two) // true

答案 1 :(得分:3)

&#34;与构造函数不同,静态工厂方法不是必需,以便在每次调用&#34;时创建新对象。这并不意味着调用静态工厂方法将必然返回相同的对象(如示例所示),只是可能(与构造函数不同)。

您可以,例如,以不同方式实现redCar(),因此它始终返回相同的对象:

class Car{
     /* snipped */

     private static final RED = new Car("red");

     public static Car redCar(){
        return RED;
     }
}

答案 2 :(得分:2)

也许汽车不是最好的例子,但考虑一个要求,即你的工厂应该每种颜色只生产一辆汽车。您可以像这样实现它(省略不必要的属性):

class Car {
    String color;

    public Car(String color) {
        this.color = color;
    }

    public static Car car(String color) {
        Car car = CARS.get(color);
        if (car != null) return car;
        car = new Car(color);
        CARS.put(color, car);
        return car;
    }

    private static final Map<String, Car> CARS = new HashMap<>();
}

查看Integer类及其工厂方法valueOf。此外,这种工厂方法对单身人士很有用(尽管他们有自己的警告)。

答案 3 :(得分:1)

您在这里创建新对象

#!/bin/bash

lockpidname="/usr/bin/plasma-overlay --nofork"

$lockpidname

check_slock () {
if [[ $(pgrep -fla $lockpidname) ]]; then 
SLOCKED=1
else
SLOCKED=0
fi
}

while true; do
  sleep 5
  check_slock
  case $SLOCKED  in 
  0) 
  echo "System unlocked run something here"
  break
  ;; 
  esac

done

静态工厂方法将首次用于创建对象一次,然后在从静态工厂方法返回时返回相同的实例。

答案 4 :(得分:1)

与所有事情一样,程序完全按照您的要求执行。如果静态方法每次调用时都使用“new”;然后每次都创建新对象。

unlike constructors static factory methods are not required to create a new object each time they're invoked"的含义是您的代码可以决定不调用new;但是例如返回一个“缓存”对象。

含义:当你使用“新”时;你叫构造函数; Java的语义导致创建 new 对象。没有办法防止它,它是硬连线的语言。

但是当你使用静态方法时,定义该方法的语义。

答案 5 :(得分:1)

工厂的工作是创建一个对象。如果您不想公开对象的创建方式,请在工厂中隐藏创建。

最近我碰巧在一个用例中工作,其中单例的概念是基于一些附加的限制来定义的。例如,捕获file1.txt的所有File对象都是singleton(或者是同一个对象)。类似地,捕获file2.text的File对象是singleton。但是捕获file1.text和file2.text的File对象是不同的。

为此,请创建一个静态全局列表,添加所谓的静态对象(例如,基于文件名)。如果您不希望Singleton(再次基于文件)对象添加到此列表,则覆盖等于。

现在,如果有人要求工厂给你一个与你在equals中指定的对象相匹配的对象(参数使两个对象相等),搜索全局列表,如果该对象存在则返回它,否则创建一个新对象,添加它到列表然后返回对象。

故事的寓意是,你不必从工厂返回新物品。您可以根据需要弯曲Singleton(如果您不需要纯Singleton)。通过使用静态工厂方法,可以调用ClassName.factory而无需实例化它。

答案 6 :(得分:0)

Bloch描述的想法是静态工厂可以使用它在请求时传递的池或缓存实例,或者决定其内部逻辑来创建新实例(可以进入缓存太)。这通常只适用于不可变对象,否则您会有一些难以跟踪的交叉对象效果。

答案 7 :(得分:0)

您提供的实施不是静态工厂。你已经完成了如下课程:

class Car{
     String color;
     Boolean spoiler;
     public static final Car car = new Car("name");

     public Car getInstance(){
        return car;
     }
     private Car(String s){
        color=s;
        spoiler = false;
     }

     public static Car redCar(){
        return new Car("red");
    }
  }

and then in main you have to call

Car.getInstance();