工厂设计模式作用(优点):
开发原则:对扩展开放,对修改关闭
- 解耦
- 单例
使用工厂模式优化类的创建:
public class Tester {
@Test
public void test() {
Accountservice accountservice = ProxyFactory.getProxy(AccountserviceImpl.class);
accountservice.transfer("tom", "jack", 100);
}
}
有多个实现类的话,切换实现类需要修改源代码,(耦合度高)
且会创建多个对象 (单例)
1、不修改源代码(松耦合):
使用反射+配置文件;
配置文件:properties xml
1、创建beans.properties
accountService=service.Impl.AccountserviceImpl
读取资源配置文件
ResourceBundle rb = ResourceBundle.getBundle(“beans”);
String className = rb.getString(key); //拿到类的全限定名
Class clazz = Class.forName(className); //反射拿到类(创建出来的实例
<----------------------------------------------------------->
…
Test测试:
public class Tester {
@Test
public void test() {
//解耦、单例
Accountservice accountservice = ProxyFactory.CreateGetProxyFactory("accountService");
accountservice.transfer("tom", "jack", 100);
}
以上解决了解耦;
2、单例:
public class ProxyFactory {
// 存放实例的容器
private static final Map map = new HashMap();
//读取配置文件
static {
ResourceBundle rb = ResourceBundle.getBundle("beans");
Enumeration<String> keys = rb.getKeys();
while (keys.hasMoreElements()){
String key = keys.nextElement();
Object factory = getProxyFactory(key);
map.put(key,factory);
}
}
public static <T> T CreateGetProxyFactory(String key) {
return (T) map.get(key);
}
//<------------------------------------------------->
public static <T> T getProxyFactory(String key) {
ResourceBundle rb = ResourceBundle.getBundle("beans");
String className = rb.getString(key); //拿到类的全限定名
//创建实例
try {
Class clazz = Class.forName(className); //反射拿到类(创建出来的实例)
final Object tt = clazz.newInstance();
//返回代理对象
return //创建代理实例
(T) Proxy.newProxyInstance(
//类加载器 原因:由于需要在程序运行时创建类的对象,并加载到JVM中运行,运行之前需要类加载
ProxyFactory.class.getClassLoader(),
//被代理类实现的所有接口(为了实现它的方法)代理类内部会根据接口进行实现
clazz.getInterfaces(),
//相当于在代理类中写的增强 当调用代理类中的任何方法时,都由该接口中的invoke方法来处理
new InvocationHandler() {
/*
Object proxy: 代理类,一般不使用该对象
Method method:被代理类中的方法对象
Object[] args 调用方法时传递的参数列表
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// method的方法调用可能有返回值
Object result = null;
//拿到方法名
String methodName = method.getName();
/*
根据方法名进行不同业务的判断,这就要求在开发的过程中,方法名不可以随便起名(开发规范)
例如,在系统开发前,公司规定,查询的方法必须以get、query、select、find开头,
其它方法不得以这些开头,这样就可以针对查询和非查询进行不同的处理
通常情况下,对于查询,需要进行性能统计;
而对于非查询要进行事务处理
*/
// 判断方法名以什么开头
if (methodName.startsWith("get")
|| methodName.startsWith("query")
|| methodName.startsWith("select")
|| methodName.startsWith("find开头")) { //查询
long start = System.currentTimeMillis();// 当前时间
result = method.invoke(tt, args); //业务核心 假设是查询业务
long end = System.currentTimeMillis();// 业务核心运行后的当前时间
long time = start - end; //耗时
System.out.println(time); //输出耗时
/*
可以采用数据库进行统计,通过反射来获取 :
clazz.getName //获取类名
clazz.getName+"."+methodName//获取方法名
后台提供查询页面
*/
} else { //非查询,加入事务
Connection connection = null;
try {
connection = JdbcUtil.getConnection();
connection.setAutoCommit(false); //开启事务
//用反射调用原有业务
result = method.invoke(tt, args); //业务核心
return result;
} catch (Exception e) {
e.printStackTrace();
try {
connection.rollback(); //事务回滚
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} finally {
try {
connection.commit(); //提交事务
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return null;
}
}
);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
测试Test:
public class Tester {
@Test
public void test() {
//解耦、单例
Accountservice accountservice = ProxyFactory.CreateGetProxyFactory("accountService");
accountservice.transfer("tom", "jack", 100);
}
工厂类 (和上面无关)
package util;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.*;
public class MyBeanFactory {
//IOC容器
private static Map<String, Object> map = new HashMap<String, Object>();
static {
readForXML(); //XML文件
// readForProp(); //properties文件
}
// <T>意思是该方法是一个泛型方法
public static <T> T getBean(String id) {
return (T)map.get(id);
}
private static void readForProp() {
try {
ResourceBundle rb = ResourceBundle.getBundle("beans");
Set<String> keys = rb.keySet();
for (String key : keys) {
System.out.println(key);
String className = rb.getString(key);
Class clazz = Class.forName(className);
Object o = clazz.newInstance();
map.put(key, o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void readForXML() {
try {
//加载xml文件到内存,生成document对象
SAXReader reader = new SAXReader(); //读取xml文件的
Document doc = reader.read(MyBeanFactory.class.getResourceAsStream("/beans.xml"));
//获取所有的bean标签(list)
List<Element> list = doc.selectNodes("//bean");
//遍历集合,获取到每个bean标签
for (Element element : list) {
//获取id属性的值作为map的key
String key = element.attributeValue("id");
//获取class属性的值,通过反射创建对象作为map的value
String className = element.attributeValue("class");
Object value = Class.forName(className).newInstance();
//将key和value放入到map中即可
map.put(key, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}