Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 什么是静态工厂方法?_Java_Design Patterns_Factory Method - Fatal编程技术网

Java 什么是静态工厂方法?

Java 什么是静态工厂方法?,java,design-patterns,factory-method,Java,Design Patterns,Factory Method,什么是“静态工厂”方法?工厂方法抽象对象实例化的方法。通常,当您知道需要实现某个接口的类的新实例,但不知道实现的类时,工厂非常有用 这在处理相关类的层次结构时非常有用,GUI工具包就是一个很好的例子。您可以简单地为每个小部件的具体实现对构造函数进行硬编码调用,但是如果您想要将一个工具箱替换为另一个工具箱,您将有很多地方需要更改。通过使用工厂,您可以减少需要更改的代码量 与构造函数不同,构造函数可以澄清代码 不需要在每次调用时创建新对象-对象 如有必要,可以缓存和重用 可以返回其返回类型的子类型

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

工厂方法抽象对象实例化的方法。通常,当您知道需要实现某个接口的类的新实例,但不知道实现的类时,工厂非常有用

这在处理相关类的层次结构时非常有用,GUI工具包就是一个很好的例子。您可以简单地为每个小部件的具体实现对构造函数进行硬编码调用,但是如果您想要将一个工具箱替换为另一个工具箱,您将有很多地方需要更改。通过使用工厂,您可以减少需要更改的代码量

  • 与构造函数不同,构造函数可以澄清代码
  • 不需要在每次调用时创建新对象-对象 如有必要,可以缓存和重用
  • 可以返回其返回类型的子类型-尤其是可以 返回调用方未知其实现类的对象。 这是许多框架中非常有价值和广泛使用的特性 它使用接口作为静态工厂方法的返回类型

我们避免提供对数据库连接的直接访问,因为它们是资源密集型的。因此,我们使用一个静态工厂方法
getDbConnection
,如果低于限制,它将创建一个连接。否则,它会尝试提供一个“备用”连接,如果没有,则会出现异常

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);
     //...
   }
}
公共类数据库连接{
专用静态最终int MAX_CONNS=100;
私有静态int totalConnections=0;
私有静态集availableConnections=new HashSet();
专用数据库连接(){
// ...
totalConnections++;
}
公共静态DbConnection getDbConnection(){
if(总连接数<最大连接数){
返回新的DbConnection();
}else if(availableConnections.size()>0){
DbConnection dbc=availableConnections.iterator().next();
可用连接。删除(dbc);
返回dbc;
}否则{
抛出新节点连接();
}
}
公共静态void returnDbConnection(DbConnection dbc){
availableConnections.add(dbc);
//...
}
}

这一切归结为可维护性。最好的方法是,无论何时使用
new
关键字创建对象,都要将正在编写的代码耦合到一个实现

factory模式允许您将创建对象的方式与处理对象的方式分开。当您使用构造函数创建所有对象时,实际上是在将使用该对象的代码硬连接到该实现。使用对象的代码“依赖于”该对象。从表面上看,这似乎不是什么大事,但当对象发生变化时(考虑更改构造函数的签名或对象的子类化),您必须返回并重新布线


今天,工厂在很大程度上被搁置在使用依赖注入的一边,因为它们需要大量的锅炉板代码,而这些代码本身有点难以维护。依赖项注入基本上等同于工厂,但允许您指定对象如何以声明方式连接在一起(通过配置或注释)。

当您希望确保只有一个实例返回要使用的具体类时,静态工厂方法很好

例如,在一个数据库连接类中,您可能只希望有一个类创建数据库连接,因此,如果您决定从Mysql切换到Oracle,您只需更改一个类中的逻辑,应用程序的其余部分将使用新连接

如果希望实现数据库池,那么也可以在不影响应用程序其余部分的情况下实现

它保护应用程序的其余部分不受您可能对工厂所做的更改的影响,这正是它的目的


它是静态的原因是,如果您想跟踪某些有限的资源(套接字连接数或文件句柄数),则此类可以跟踪传递和返回的数量,这样您就不会耗尽有限的资源。

静态工厂方法可以提高可读性:

比较

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.

是封装对象创建的一种方法。如果没有工厂方法,您只需直接调用类的:
foox=newfoo()
。使用此模式,您可以调用工厂方法:
foox=Foo.create()
。构造函数被标记为private,因此只能从类内部调用它们,而工厂方法被标记为private,这样就可以在没有对象的情况下调用它

这种模式有一些优点。一个是工厂可以从许多子类(或接口的实现者)中选择并返回该子类。这样,调用方可以通过参数指定所需的行为,而不必知道或理解潜在的复杂类层次结构

另一个优势是,正如Matthew和James所指出的,控制对有限资源(如连接)的访问。这是一种实现方法——如果构建和销毁过程成本高昂,那么一次构建并回收它们可能更有意义,而不是构建、使用和拆卸对象。factory方法可以返回现有的、未使用的实例化对象(如果有),或者在对象计数低于某个较低阈值时构造一个,或者在高于较高阈值时抛出异常或返回
null

根据维基百科上的文章,多工厂方法也允许对类似的参数类型进行不同的解释。通常,构造函数与类具有相同的名称,这意味着您只能有一个具有给定名称的构造函数。工厂没有那么多限制,这意味着你可以有两个dif
public class Foo{
  public static Foo createWithBar(){
    //...
  }

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

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();
Coordinate c = Coordinate.createFromCartesian(double x, double y)
Coordinate c = Coordinate.createFromPolar(double distance, double angle)
class Test{
 int x, y;
 private Test(){
  .......
  .......
  }
}
public static Test getObject(){
  return new Test();
}
Test t = Test.getObject();
//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();
  }
}
public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
}
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;
    }
}