TintySpring构建过程 Step2-抽象工厂
之前的简单工厂存在着很多问题。在这一步中我们要尝试解决一部分不合理的问题。
原来的工厂在生成Bean的时候采取的是new的形式,这样是很不合理的,我们希望容器能够根据我们的配置在自动的装配相应的对象到我们的工厂类之中。所以在这里我们需要通过类的包位置来创建相应的对象,我们先实现用默认构造方法来生成Bean。
-
我们将
BeanFactory
抽象出来,因为之后我们需要做到各种形式的BeanFactory
,比如构造函数创建Bean,或者要注入的等等。BeanFactory
肯定有两个方法getBean
和registerBeanDefinition
。第一个方法用来获取Bean第二个用来注册Bean。我们可以把它做成一个接口:public interface BeanFactory { Object getBean(String name); void registerBeanDefinition(String name, BeanDefinition beanDefinition); }
-
现在根据这个抽象工厂我们实现一个工厂类
AbstractBeanFactory
:public abstract class AbstractBeanFactory implements BeanFactory { private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(); @Override public Object getBean(String name) { return beanDefinitionMap.get(name).getBean(); } @Override public void registerBeanDefinition(String name, BeanDefinition beanDefinition) { Object bean = doCreateBean(beanDefinition); beanDefinition.setBean(bean); beanDefinitionMap.put(name, beanDefinition); } /** * 初始化bean * @param beanDefinition * @return */ protected abstract Object doCreateBean(BeanDefinition beanDefinition); }
这个工厂对象是一个抽象的工厂方法,实现了getBean
和registerBeanDefinition
两个方法,并有一个抽象方法doCreateBean
。这是为了继承它的其他工厂对象能够根据自己的方式来创建Bean,因为不同的工厂类在创建Bean上的方式是不一样的。比如有的需要注入已创建的对象,有的需要注入属性等等。
-
现在我们实现一个工厂类
AutowireCapableBeanFactory
public class AutowireCapableBeanFactory extends AbstractBeanFactory { @Override protected Object doCreateBean(BeanDefinition beanDefinition) { try { Object bean = beanDefinition.getBeanClass().newInstance(); return bean; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } }
这个工厂类根据得到的ClassName来创建相应的对象,达到Bean工厂的效果。
-
我们的
BeanDefinition
也要根据我们现在传入ClassName做出一些修改,主要是能够设置ClassName以及根据ClassName得到Class,因为这个类就是用来和BeanFactory做适配用的:public class BeanDefinition { private Object bean; private Class beanClass; private String beanClassName; public BeanDefinition() { } public void setBean(Object bean) { this.bean = bean; } public Class getBeanClass() { return beanClass; } public void setBeanClass(Class beanClass) { this.beanClass = beanClass; } public String getBeanClassName() { return beanClassName; } public void setBeanClassName(String beanClassName) { this.beanClassName = beanClassName; try { this.beanClass = Class.forName(beanClassName); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public Object getBean() { return bean; } }
-
测试一下:
public void test() { // 1.初始化beanfactory BeanFactory beanFactory = new AutowireCapableBeanFactory(); // 2.注入bean BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setBeanClassName("us.codecraft.tinyioc.HelloWorldService"); beanFactory.registerBeanDefinition("helloWorldService", beanDefinition); // 3.获取bean HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService"); helloWorldService.helloWorld(); }
问题1:为什么我们要把Factory设计成接口-->抽象类-->具体实现类
这样呢?
问题1分析:接口相当于角色,抽象类相当于人物模板,具体实现类就相当于人物。人物可以有多种角色,人物模板实现多种角色,然后这种模板就对应于具体你要实现的类,方便你去在任务模板上自定义人物属性。接口的好处在于,当我只需要关心你是某个角色时,可以直接调用接口,而不需要知道你具体的接口和方法。这样三层的设计模式在Spring中经常会使用到,是一种扩展性很强的设计模式。