工厂模式:
工厂模式:用于程序间的解耦合。
耦合:程序间的直接相互调用
初级工厂
//BeanFactory.class
public class BeanFactory {
public static ICustomerService getCustomerService(){
try {
return (ICustomerService) Class.forName("com.layman.Service.Impl.ICustomerServiceImpl").newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static ICustomerDao getCustomerDao(){
try {
return (ICustomerDao) Class.forName("com.layman.Dao.Impl.CustomerDaoImpl").newInstance();
}catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//Client.class
public class Client {
public static void main(String[] args) {
//使用反射的方式
ICustomerService service = BeanFactory.getCustomerService();
service.saveCustomer();
}
}
//CustomerDaoImpl.class
public class CustomerDaoImpl implements ICustomerDao {
@Override
public void saveCustomer() {
// TODO Auto-generated method stub
System.out.println("持久层保存用户");
}
}
- 这个就是使用反射的机制 来实例化对象。而不是使用new的方式。
上面所写虽然耦合解开 但是每个对象的获取都需要一个get方法
- 解决方式:使用properties配置文件。
中级工厂
//perproties配置文件
CUSTOMERSERVICE=com.layman.Service.Impl.ICustomerServiceImpl
CUSTOMERDAO=com.layman.Dao.Impl.CustomerDaoImpl
//BeanFactory.java
public class BeanFactory {
//1.定义一个properties对象
private static Properties props = new Properties();
//2.使用静态代码块给对象赋值
static{
try{
InputStream in =BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
}catch(Exception e){
throw new ExceptionInInitializerError("读取配置文件失败"+ e);
}
}
}
public static Object getBean(String beanName) {
try {
// 1.读取配置文件,跟beanName获取全限定类名
String beanPath = props.getProperty(beanName);
return Class.forName(beanPath).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//Client.class
public class Client {
public static void main(String[] args) {
//使用反射的方式
ICustomerService service = BeanFactory.getBean("CUSTERMERSERVICE");
service.saveCustomer();
}
}
- 这样就解决了每个类都需要get方法的弊端。
- 这是一个不错的方法,使用了输入流和类加载器。但是存在一个更加简单的方法:使用ResourceBundle类
高级版
public class BeanFactory {
// 1.只能用于读取properties文件,别的读不了
// 2.只能用于读取,不能用于写入
// 3.只能读取类加路径下的,不在类路径下读取不了
// 4.方法参数的写法是 包名+文件名(不需要扩展名)
private static ResourceBundle bundle = ResourceBundle.getBundle("bean");
public static Object getBean(String beanName) {
try {
// 1.读取配置文件,跟beanName获取全限定类名
String beanPath = bundle.getString(beanName);
return Class.forName(beanPath).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
return beans.get(beanName);
}
}
public static Object getBean(String beanName) {
try {
// 1.读取配置文件,跟beanName获取全限定类名
String beanPath = bundle.getString(beanName);
return Class.forName(beanPath).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
- 创建一个ResourceBundle类,使用它的静态方法getBundle(fileName);来读取配置文件,但是不可以写入,且文件必须要在类路径下,因为它是基于classLoader实现的。
- 这样的工厂模式虽然很好,但是在每一次调用getBean(String beanName)方法的时候都会重新创建一个bean对象。
- 解决方案:使用Map<String,Object>。来提前遍历bean.perporties文件,并创建对应的对象。getBean(String beanName)方法直接返map中的对象。
终极版
public class BeanFactory{
// 1.只能用于读取properties文件,别的读不了
// 2.只能用于读取,不能用于写入
// 3.只能读取类加路径下的,不在类路径下读取不了
// 4.方法参数的写法是 包名+文件名(不需要扩展名)
private static ResourceBundle bundle = ResourceBundle.getBundle("bean");
// 定义一个容器,用来存放我们要使用的对象
private static Map<String, Object> beans = new HashMap<String, Object>();
// 使用静态代码块初始化map
static {
// 1.读取配置文件中所有的配置:key部分
Enumeration<String> keys = bundle.getKeys();
// 2.遍历keys
try {
while (keys.hasMoreElements()) {
// 3.取出一个key
String key = keys.nextElement();
// 4.根据key获取beanPath
String beanPath = bundle.getString(key);
// 5.根据beanPath反射创建类对象
Object value = Class.forName(beanPath).newInstance();
// 6.把key和value存入map中
beans.put(key, value);
}
} catch (Exception e) {
// TODO Auto-generated catch block
throw new ExceptionInInitializerError("容器创建失败,停止执行");
}
}
public static Object getBean(String beanName) {
return beans.get(beanName);
}
- 使用ResourceBundle对象来读取配置文件,然后创建使用的容器,接着使用静态代码块来遍历keys并实例化对象。最后getBean(String beanName) 所返回的就是map容器中的对象,这样所有的线程都是使用的同一个对象。