研究了一下工厂模式,对它的应用场景和网上的众多说法进行了思考,总结如下。
几个疑问点:
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); } }
到这里,工厂模式算是有了自己的理解,欢迎交流,欢迎挑战