今晚看代码的时候看到工厂类中方法和参数都使用static修饰,于是很好奇的想为什么一定要使用静态方法。百度了一下,发现百度了一堆垃圾,根本没有找到自己想要的答案。后来去Stack Overflow,果然找到了相关的问题。因为是英文的,所以翻译过来并综合整理了一下。
为什么要在工厂模式中使用静态方法
工厂模式是一种封装对象创建的方法。如果不使用工厂模式,你就需要直接使用构造方法来创建对象:
Foo x = new Foo()
使用工厂模式,就可以取而代之的调用工厂方法:
Foo x = Foo.create()
工厂类的构造方法被标记为private,所以构造方法除了在类的内部被调用以外就不能够被访问。工厂类的其他方法被标记为static,这样就不需要在调用该方法之前必须首先拥有一个该类的对象。
使用工厂模式有一些好处。其一工厂类可以从许多子类(subclasses)(或者一个接口的实现)并返回它( One is that the factory can choose from many subclasses (or implementers of an interface) and return that. )。用这种方式调用方法可以通过参数来确定类的行为而不需要知道或者理解类的潜在的复杂层次(This way the caller can specify the behavior desired via parameters, without having to know or understand a potentially complex class hierarchy.)。
另一个好处是,控制对一个有些资源的访问,比如数据库连接(connection)。这是一种实现重用对象池(pools of reusable objects)的方法而不是简单粗暴的先实例化对象,然后使用并销毁对象。如果实例化和销毁对象的代价很高,那么建立一次并重复使用对象就显得意义非凡了。工厂方法可以返回一个已经实例化了但么有被使用的对象;或者如果对象数量小于指定的对象数量时,可以直接实例化一个对象;或者如果对象数量大于了指定的对象数量的时抛出异常并返回null。
下面是一个数据库连接的工厂类的简单实现:
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 db) { //... } }
多个工厂方法也可以允许对相似参数类型的不同解析。通常构造方法有与类相同的名字,这意味着如果给定一个签名(signature)你就只能拥有一个构造方法。工厂模式则没有这么多的限制。也就是说你可以有不同的方法但是却接收相同的参数类型:
Coordinate c = Coordinate.createFromCartesian(double x, double y) Coordinate c = Coordinate.createFromPolar(double distance, double angle)
这可以用来提高代码的可读性。
比较下面的两种不同方式:
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.
public class Foo{ public static Foo createWithBar(){ //... } public static Foo createWithoutBar(){ //... } } // ... // This is much easier to read! Foo foo = Foo.createWithBar();
欢迎转载,转载请注明出处。
浙公网安备 33010602011771号