这一部分比较杂乱
1.接口与工厂方法模式
正常两个对象object互相调用的代码是这个样子:
DataCatch dc1=new DataCatch(); try{dc1.OpenConnACRPMM();}catch(Exception ex){out.println("Test-error");} Vector v1=new Vector(); v1=dc1.testF("select 部门,分类 from 部门分类 ORDER BY 部门 DESC");
因为上述写法,属于强耦合,我们要解耦和
面向对象给我们提供的思路就是 接口,用接口+工厂方法模式 的形式,进行解耦
具体来说: 类 = 接口 + 工厂
上图中,导演代表“工厂” 角色代表“接口”
过去 剧本和演员这两个 object实体,也就是class类,是紧密耦合的,表现在代码上就是:
public class Script{ public void setMove(){ Bell bell = new Bell(); bell.cry(); } }
真的很土,显式调用,两个类强耦合
现在解耦和,让剧本类(Script)和演员贝尔(Bell)不在直接调用
方法是:让剧本(Script)只操作角色(Charactor),与演员贝尔完全脱离关系
表现在代码上如下:
//接口注入需要的接口 public interface Injectable{ void injectChara(Charactor batman); } //剧本类 public class Script implements Injectable{ Charactor batman; //下面展示三种注入方式 //1.构造函数注入 public Script(Charactor batman){ this.batman = batman; } //2.属性注入 public void setChara(Charactor batman){ this.batman = batman; } //3.接口注入 public void injectChara(Charactor batman){ this.batman = batman; } //剧本需要的动作 public void setMove(){ //在此剧本需要batman去哭 //下面的代码表明 剧本 使用了 batman这个实例 //也就是产生了依赖关系 batman.cry(); } } //角色类 public interface Charactor{ //角色 哭的动作 void cry(); } //演员“克里斯蒂安贝尔”类 public class Bell implements Charactor{ public void cry(); } //导演类 public class Director{ //创建剧本 下面开始应对不同的注入方式 //1.构造函数注入 Charactor batman = new Bell(); Script BM1 = new Script(batman); //2.属性注入 Charactor batman = new Bell(); Script BM1 = new Script(); BM1.setChara(batman); //3.接口注入 Charactor batman = new Bell(); Script BM1 = new Script(); BM1.injectChara(batman); //下面让 剧本去操作bell BM1.setMove(); }
上面的图和代码说明了一件事 类 = 接口 + 工厂(Thinking in JAVA在interface那一章里最后举得例子,我觉得是一个接口注入的例子)
如果现在换演员,让Pitt去演的话,只需要增加一个Pitt类,但是剧本方面的代码不用修改
这样你就做到了 Script 与Bell完全无关,代码上没有互相侵入
但是上面代码的缺陷是,本质上来说,你还是在代码中写了常量,只是不写在剧本类中了,而是写在了导演类中。
实际上那些信息最好是写在xml文件中,或者某个静态的文件或者数组中。然后让代码去读取那个文件,这也是spring的基本思想。
上面说得很浅显,如果具体地说,就是工厂和接口能够替代类,上层不需要知道下层发生了怎样的变化,也就是说,解除了上层对于下层的依赖Dependency
如果用在实际代码中,比如数据库连接的部分,业务模块 需要调用数据库封装的类去操作数据库,比如有mysql access oracle,你不能让业务模块同时实现三种数据库访问的代码,那样太土了
你需要的是 将业务模块与数据库访问类 解耦和
你首先分别封装mysql access 和 oracle的数据库操作
然后对他们进行抽象,也就是有一个接口
让你的各个业务模块面向接口编程
然后,你需要一个“数据库工厂”,让它决定你需要使用哪个数据库访问类
涉及到这个问题,我们不如说得实际一点,连接一个数据库你需要的常量 包括: 服务器url, 用户名, 密码, 数据库名等
这些常量保存在哪里呢?
基本思想是,不管保存在哪里,你都不能把它们写到代码里。
那么你的数据库工厂如何判断你使用哪个数据库访问类呢?
在java的环境中用spring的观点来看,你需要用spring框架里的内容,具体地说就是spring容器,你把静态常量写到xml的配置文件中,你在java代码中只需要加载这个xml文件,然后在代码中读取其中的内容,就能让程序明白需要访问哪个数据库了。
spring框架这部分观点的核心其实是java的反射机制
java反射机制的核心就是,你用java的这部分语言特性,创建一个对象,然后读取一个外部xml文件中的常量,这样初始化这个对象。
从效果上看,你的代码中就没有任何静态常量了。
依据上述思路,spring用java语言进行了封装,创造了自己的实现方式。
实际上php也支持反射机制
而且,从代码的角度看,phpcms中也某种程度借鉴了这种方式
1. load_sys_class()方法实际上类似于spring中的Resource BeanFactory等类的方法,去加载一个xml文件,不同的是phpcms加载的是array数组config文件夹中的数组,数组中保存的就是服务器url 用户名密码之类的常量。
java下spring的视角是这样的:它封装了工厂方法模式和接口
让我们来捋顺一下:我们要解决的问题是IoC控制反转 依赖注入
你,一个调用者,声明一个类class的实例(实例化),你初始化它(它指的是被调用者),也就是你,依赖 它。
但是如果做到了控制反转,你就不用实例化以及初始化它了。
你只需要在自己(调用者)的空间里 声明它,它自己就被容器(Spring容器)实例化甚至初始化了。
假如被调用的是一个拥有接口的类,那么你只需要在自己(调用者)的空间里声明它的接口,那么容器会帮助你实例化一个它的实现类,并把该实例返回给你。
这样你就很潇洒了,因为,你是面向接口编程,而不是类。
spring的做法是,通过1.xml配置文件 2.@注解方式 3.java类@configuration方式,三种方式预先注册class
spring是一个框架,或者可以认为也是一个服务器,你需要启动它,也可以关闭它。
当你启动了spring框架,它会首先读取applicationcontext.xml类似的一个文件,去扫描其中一个属性中配置的文件夹下的所有bean,把他们全部实例化,并且放在spring自己的bean实例池中,等待被使用。
接下来,spring框架会继续读applicationcongtext.xml这个文件下面,直接配置的xml方式配置的bean 把它们实例化 并放置到spring的bean实例池中,等待被使用
然后,你在写代码的时候,只需要在需要使用某个类(或者叫bean)的时候,@Autowired+声明语句 就可以了,那么看似,你只是声明了一个类,实际上,你已经获取了预先被注册的 对应的实例。
我们为什么这么做?还是那句话,为了牛逼。因为你想想,你为什么要费这么大劲?因为你想解除你(调用者)对它(被调用者)的依赖,你想要解耦合。
你调用他,依赖他的目的只有一个,使用它的方法。
有的傻逼是蟑螂,你把它当人,它你妈逼不把自己当人,对这种傻逼就不能心慈手软,操你妈就要把它“打倒在地,踩上一万脚,永世不得翻身”
傻逼,你妈逼,我草你妈
Just when I thought that I was out they pull me back.