您的位置:首页 > 其它

接口工厂方法模式解耦与反射机制 Just when I thought that I was out they pull me back

2015-10-29 09:34 232 查看
这一部分比较杂乱

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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: