研究了一下工厂模式,对它的应用场景和网上的众多说法进行了思考,总结如下。
几个疑问点:
1、网上说用factory,就可以不用自己new了,但是疑问在于,不直接依赖,转而间接依赖,作用是什么?节省了代码量?易于扩展?
2、书上说,一个系统要独立于它的产品的创建、组合和表示时。一个系统要由多个产品系列中的一个来配置时。当你要强调一系列相关的产品对象的设计以便进行联合使用时。当你提供一个产品类库,而只想显示它们的接口而不是实现时,就应该使用工厂模式。但是疑问在于,这他妈说的都是啥?
于是开始了我的思考过程,思路如下:
1、书上说的,等我领悟了,我就成仙了,作者这么写书,或者翻译的人这么写,就是没道德,根本不考虑看书的人的感受,这里不多吐槽了,免得跑题
2、开始思考网上的众多说法,试图发现他们背后的出发点。
-如果说代码量节省,其实照着网上的demo来看,表面上想一下,并没有节省多少代码,反而多了很多接口,但是如果在大工程里,类很多又会怎么样呢?如果仅仅是简单的把new改成getFromFactory,显然是没有发挥出factory的优势。
-如果说解耦,确实是,不过原来的直接依赖,改成间接依赖,有什么作用呢?好像没什么作用,因为消费者依然要向工厂索要自己想要的类型
以上思考没有答案后,开始试图找到现实中的例子,然后考虑其实际意义,然后就想到了spring的beanFactory,这是个典型的工厂模式,那么它的意义在于什么呢?我决定顺着spring往里找答案。
n年前面试的时候,被问到过,“用了ioc有什么好处”?我答到,“不用new了”,问,“那我不用spring,全都自己new又怎么样呢?”,我无语。不过如果现在让我再次回答这个问题,我会说:“解耦、对bean的统一管理、实现了依赖关系的反转”
而“对bean的统一管理、实现依赖关系的反转”,正是靠factory模式实现的。
试想一下复杂的场景,我作为一个对外提供bean的管理员,想给所有从我这里出去的bean打个标签,怎么做?我想统一要求,我给出的bean,被调用的时候,都要发个消息给我,以统计调用次数,怎么做?前提是不能改变bean内部的逻辑?(实际上也不可能一个一个的去改),答案就是factory+proxy,这就是统一的管理
再考虑另一个问题——ioc,当使用了factory模式,factory即充当了一个bean依赖关系的维护者,即从原来的A必须依赖B实现一个功能,变成了,A实现功能不知道要依赖谁,factory告诉它,这里网上的demo就有一个容易让人误解的地方:从原来的new改成getFromFactory(“beanName”),我就是这里想不清楚——这依赖关系其实没变,只是多了一层而已。但是实际上不是,spring的bean管理,是通过从属于spring的配置文件来维护bean的依赖关系的,实际互相调用前,spring早就按照这份管理文件将各个bean装配好了,这就是所谓的控制反转了
这样bean的功能变得更单一,复杂的关系维护交给了工厂,到这里也就没什么疑惑的了,随即写了一段程序,模拟了spring的加载bean的过程:
工厂接口:
public interface AbstractFactory {
Object getBean(String beanName);
}
工厂实现:
public class ApplicationContext implements AbstractFactory {
private BeanDefinitionRegistry beanMapper = new BeanDefinitionRegistry();
private Map<String,Object> beans = new HashMap<String,Object>();
public Object getBean(String beanName) {
return beans.get(beanName);
}
public ApplicationContext () {
init();
}
private void init() {
loadBean();
wireBean();
}
private void wireBean() {
for (Entry<String,Object> entry : beans.entrySet()) {
Object bean = entry.getValue();
Class c = bean.getClass();
Field[] fields = c.getDeclaredFields();
wireField(fields,bean);
}
}
private void wireField(Field[] fields,Object bean) {
for (Field field : fields) {
try {
field.setAccessible(true);
Object value = field.get(bean);
if (value == null) {
field.set(bean, beans.get(field.getName()));
}
} catch (Exception e) {}
}
}
private void loadBean() {
for (Entry<String, Object> entry : beanMapper.getBeanDefinition().entrySet()) {
doLoadBean(entry.getKey(),entry.getValue());
}
}
private void doLoadBean(String key, Object value) {
Class c = (Class)value;
try {
Object o = c.getConstructor().newInstance(null);
beans.put(key, o);
} catch (Exception e) {}
}
}
bean的配置模拟:
public class BeanDefinitionRegistry {
public Map<String,Object> beanDefinition = new HashMap<String,Object>();
public BeanDefinitionRegistry() {
beanDefinition.put("serviceA", ServiceA.class);
beanDefinition.put("serviceB", ServiceB.class);
}
public Map<String, Object> getBeanDefinition() {
return beanDefinition;
}
}
两个有依赖关系的服务:
public class ServiceA {
private ServiceB serviceB;
public ServiceB getServiceB() {
return serviceB;
}
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
public String getCurrentDate() {
return serviceB.getCurrentDate();
}
}
public class ServiceB {
public String getCurrentDate() {
return new Date().toString();
}
}
最后的测试类:
public class Tester {
public static void main(String[] args) {
AbstractFactory beanFactory = new ApplicationContext();
ServiceA serviceA = (ServiceA)beanFactory.getBean("serviceA");
String currentDate = serviceA.getCurrentDate();
System.out.println(currentDate);
}
}