静态工厂方法的作用

        只列举常用的几个       

        一,单例        

        一个普通类可以有自己的静态工厂方法, 从而使类自己遵守单例模式.即这个类只能实例化一次,外部也只能通过静态工厂方法获取到这个类的唯一实例.示例如下:

/**
 * 通过静态工厂方法的方式,将一个类设计为单例
 */
public class ClassA {
	private static final ClassA a = new ClassA(); //用静态final域引用ClassA的唯一实例
	
	//构造方法要设为私有
	private ClassA(){	
	}
	
	public static ClassA getInstance(){	//使用静态工厂方法返回唯一实例的引用
		return a;
	}

}

        需要注意的是,有两种特殊情形下,上面设计单例的方式会有问题:

        1,通过反射机制,可以调用私有的构造器. 

        解决办法: 可以在私有构造函数中通过设计一个类的静态计数器字段,判断私有构造函数是否第一次被调用,如果不是,那么可以抛出异常.

        2,可序列化的类每次反序列化时都会创建一个新的实例.

        解决办法:可以在类中加入private Object readResolve()方法返回静态final域引用的唯一实例来避免重复创建对象.

        扩展: 实现单例的最佳方法是编写一个包含单个元素的枚举类型.

        参见文章: 《浅谈java中单例的设计》

        

        二,在工厂类中,用于定制同一接口的不同实现的实例,或者是同一父类的不同子类的实例.示例如下:

class People {
}
class Father extends People {
}
class SonA extends Father {
}
class SonB extends Father {
}

public class PeopleFactory {
	/**
	 * 使用静态工厂方法,通过传入参数定制不同的People实例
	 * @param id
	 * @return
	 */
	public static People getPeopleInstance(char id) {
		switch (id) {
		case 'F':
			return new Father();
		case 'A':
			return new SonA();
		case 'B':
			return new SonB();
		default:
			return new People();

		}
	}

}

        

        三,灵活的静态工厂方法,也构成了"服务提供者框架"的基础.

        就拿JDBC举例,JDBC是java编程与数据库交互的接口,它仅是一种规范,不同的数据库厂商,如oracle,mysql等等,根据这个规范的JDBC接口,写出针对自己数据库的JDBC实现,所以在java编程与数据库交互时,要根据数据库的不同导入JDBC不同的实现的 jar 包,才能正确地与数据库打交道.

        以使用JDBC连接MySql为例:

Class.forName("com.mysql.jdbc.Driver");   
DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test","root","root");  
        在这里,Driver是JDBC定义的 服务提供者接口, com.mysql.jdbc.Driver是MySql提供的实现类.在使用 静态工厂方法Class.forName()加载 com.mysql.jdbc.Driver类时,Driver类会创建自己的实例并 向 DriverManager 注册实例;而Connection是 服务接口,通过调用 静态工厂方法getConnection()以及传入的参数获取Connection服务接口的实现的实例.而这个实现是MySql厂商提供的,DriverManager会通方法的传入参数配对已注册的服务提供者,从而找到对应的服务提供者提供的服务(Connection实现).

        可以以一种简洁的方式去理解静态工厂方法在这里充当的角色.如下面代码所示,理解时可把JDBC接口规范比作Car,把Audi(奥迪)比作oracle的JDBC实现,把Benz(奔驰)比作mysql的JDBC实现,以此类比......我与数据库打交道,是通过JDBC接口,同样,我与车打交道,是通过Car接口;真正与数据库打交道时,比如跟oracle,那么就要加载oracle的JDBC实现;同样,真正与车打交道时,比如Audi(奥迪),那么就要加载Audi这个车的实现,如下代码所示,只要把Audi的类全名当作参数传给静态工厂方法,那么就能获取到实打实的Car实例了,而且这个Car实例是和Audi打交道的,与Benz(奔驰)或者(BMW)宝马没有关系.

        如下面代码所示:

interface Car {
	public void printName();
}
class Audi implements Car {

	@Override
	public void printName() {
		System.out.println("奥迪");
	}
}
class Benz implements Car {

	@Override
	public void printName() {
		System.out.println("奔驰");
	}
}
class BMW implements Car {

	@Override
	public void printName() {
		System.out.println("宝马");
	}
}

public class Factory {
	/**
	 * 通过静态工厂方法,传入实现Car接口的实现类的全名,获取该实现类的实例
	 * @param className
	 * @return
	 * @throws Exception
	 */
	public static Car getCarInstance(String className) throws Exception {
		Class cl = Class.forName(className);
		Car car = (Car) cl.newInstance();
		return car;
	}
	
	public static void main(String [] args) throws Exception{
		Car car = getCarInstance("Audi");//把Audi的类全名当作参数传给静态工厂方法
		car.printName();
	}

}
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值