概述
spring是一款 轻量级、 提供 容器化依赖注入、和 AOP面向切面编程的实现的框架。
依赖注入:
传统的创建对象都需要手动创建,那么会使我们修改不方便,比如,我们可能会需要切换实现类,或者挪动类的位置,比如:
public class Main{
public class List<Integer> list = new ArryayList<>();
}
// 如果我们需要切换List的实现类,那么必须手动修改为如下
public class Main{
public class List<Integer> list = new LinkedList<>();
}
// 这样叫做有侵入性的代码修改方式,表示我们需要重新修改源代码,以适应新的要求
传统的方式的 需要修改源代码 而且数量庞大的话很麻烦,比如:我们有一百个引用List的地方,都想切换,那么我们怎么做才能实现较好的替换呢?可以用个 工厂。
其实我个人来说,很多人,包括我自己,没接触过过设计模式的话,很难去想到工厂是啥?
但是:我们基本都能想到,需要加一个中间层,让所有的获取对象引用这个对象或者把这个对象放到一个容器里,类似这样
最简单版本,所有的类都引用这个类的list对象,只需要修改这一个类,别的类就可以修改了。:
public class ObjectPool {
// 单例
public static List<Integer> list = new ArrayList<>();
}
public class ObjectPool {
// 非单例
public static List<?> getList() {
return new ArrayList<>();
}
}
n个不同的接口就需要写n个属性或者写n个方法,不好维护。
那么可以改成这样,一劳永逸:
// 所有的对象获取这个对象,默认单例
public class ObjectPool {
// 记录类对应的对象
public static Map<Class<?>, Object> objectMap = new HashMap<>();
// 记录类对应的实现类
public static Map<Class<?>, Class<?>> implMap = new HashMap<>();
// 根据类获取对象
public static <T> T getObject(Class<T> cls) {
T res;
// 如果已经实例化过,直接获取
res = objectMap.get(cls);
// 未实例化过,根据实现类创建对象,返回对象
if (res == null) {
Class<?> implClass = implMap.get(cls);
// 如果没有指定实现类,那么就采用原来的类
if (implClass == null) {
implClass = cls;
}
// 创建对象
Object obj = implClass.getConstructor().newInstance();
// 把对象放入map,以便后续使用
objectMap.put(cls, obj);
res = (T)obj;
}
return res;
}
// 设置实现类
public static void setImpl(Class<?> cls, Class<?> implCls) {
implMap.put(cls, implCls);
}
}
然后,我们如果需要改动,可以直接修改该类的实现类。用别的方式来指定实现类
如果我们需要对于每一个对象都创建一个新对象呢?
上面的代码简单修改就可以了
// 所有的对象获取这个对象,默认单例
public class ObjectPool {
// 记录类对应的实现类
public static Map<Class<?>, Class<?>> implMap = new HashMap<>();
// 根据类获取对象
public static <T> T getObject(Class<T> cls) {
T res;
// 获取实现类
Class<?> implClass = implMap.get(cls);
// 如果没有指定实现类,那么就采用原来的类
if (implClass == null) {
implClass = cls;
}
// 创建对象
Object obj = implClass.getConstructor().newInstance();
res = (T)obj;
return res;
}
// 设置实现类
public static void setImpl(Class<?> cls, Class<?> implCls) {
implMap.put(cls, implCls);
}
}
其实可以组合成这样:
// 所有的对象获取这个对象,默认单例
public class ObjectPool {
// 是否为单例模式
public static boolean isSingleton = true;
// 记录类对应的对象
public static Map<Class<?>, Object> objectMap = new HashMap<>();
// 记录类对应的实现类
public static Map<Class<?>, Class<?>> implMap = new HashMap<>();
// 根据类获取对象
public static <T> T getObject(Class<T> cls) {
T res;
if (isSingleton) {
// 如果已经实例化过,直接获取
res = objectMap.get(cls);
}
// 未实例化过,根据实现类创建对象,返回对象
if (res == null) {
Class<?> implClass = implMap.get(cls);
// 如果没有指定实现类,那么就采用原来的类
if (implClass == null) {
implClass = cls;
}
// 创建对象
Object obj = implClass.getConstructor().newInstance();
if (isSingleton) {
// 把对象放入map,以便后续使用
objectMap.put(cls, obj);
}
res = (T)obj;
}
return res;
}
// 设置实现类
public static void setImpl(Class<?> cls, Class<?> implCls) {
implMap.put(cls, implCls);
}
// 设置是否为单例模式
public static vodi setSingleton(boolean isSingleton) {
this.isSingleton = isSingleton;
}
}
上面的实现是一种简单的实现,可以看到,我们的改动减小到了一个类中。
上面的代码还是要修改类,如果可以用另一种方式来描述就好了,xml就是spring选用的方式。
用xml描述类的实现关系,修改只需要修改xml即可,代码无需修改就可以切换到相同接口的另一个实现类。
后续我发现了问题,在于这种方式只能确定一种类型的实现,如果项目中有部分List
想要使用ArrayList
,有一部分想要使用LinkedList
我们又该如何使用IOC容器来控制呢?
所以,我们的IOC的Map实现可以修改为Map<String id, Class<?> cls>
这样我们可以对于不同的需要list的场景按照ID进行分类,从而控制。所以,代码整体类似,不过需要修改的就是Map的结构罢了。
(不过为了方便,也可以针对没有传入id的,按照默认的类型首字母小写来方便不写id)
这种IOC:(使用容器帮助创建对象)的好处在于:
- 低耦合
- 方便修改
关于工厂,就是工厂模式,也是用来根据传入类型的不同来创建对象的。我觉得它的不好处也在于,如果需要控制的类太多,要写n个工厂,这种方式可以不写很多工厂。