Spring的基本应用(1):依赖以及控制反转
在说到这里的时候,首先要说下程序的耦合和解耦,以便对上节做一个解释。
一、程序的耦合和解耦
1.程序的耦合性(Copling)
(1)程序的耦合性,也叫做耦合度,是对模块之间关联程度的度量,耦合性的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合性是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系,模块间的联系越多,程序的耦合性越强,独立性越差,也即降低耦合性可以提高其独立性。
(2)在软件工程中,耦合性就是对象之间的依赖性,对象的耦合越高,维护的成本越高。因此对象的设计应该使得类和构建之间的耦合性最小,软件工程中通常使用耦合度和内聚度来作为衡量模块的独立程度的标准,划分的一个标准是高内聚低耦合。
(3)内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。
2.接下来将用案例的方式来演示程序的耦合。
(1)code
package com.itheima.jdbc; import java.sql.*; /**
* 程序的耦合
*/
public class JdbcDemo1 {
public static void main(String[] args) throws Exception {
//1.注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/eesy","root","root");
//3.获取操作数据库的预处理对象
PreparedStatement pstm = conn.prepareStatement("select * from account");
//4.执行sql语句,得到结果集
ResultSet rs=pstm.executeQuery();
//5.遍历结果集
while (rs.next()){
System.out.println(rs.getString("name"));
}
//6.释放资源
rs.close();
pstm.close();
conn.close();
}
}
(2)如上代码中,程序要想运行,没有new com.mysql.jdbc.Driver()这个jar包是不能够运行的,没有jar包会直接在编译期的时候就报错,并不是运行期的异常,在实际开发过程中,有很多这种在编译期就直接报错的代码,
就是说明这个类运行的时候,没有这个jar包的时候,是不能够正常编译的,这个特性就是我们说的程序的耦合性,对于耦合,我们一般认为是程序之间的依赖关系,即类之间的依赖,方法之间的依赖,耦合性只能降低,但是不能够完全的消除依赖关系。在实际开发中,我们应该做到,编译期不依赖,运行时才依赖。

(3)我们可以通过下面的这种方式来降低耦合性。
package com.itheima.jdbc; import java.sql.*; /**
* 程序的耦合
*/
public class JdbcDemo1 {
public static void main(String[] args) throws Exception {
//1.注册驱动
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/eesy","root","root");
//3.获取操作数据库的预处理对象
PreparedStatement pstm = conn.prepareStatement("select * from account");
//4.执行sql语句,得到结果集
ResultSet rs=pstm.executeQuery();
//5.遍历结果集
while (rs.next()){
System.out.println(rs.getString("name"));
}
//6.释放资源
rs.close();
pstm.close();
conn.close();
}
}
(4)使用类加载的形式来加载一个字符串,我们不再依赖于某个具体的驱动类。这样带来的好处就是可以使得这个类比较独立,
能通过编译期,就算要报错,最后也是在运行时报错。所以我们解决类依赖的基本思路是:在创建对象的时候,使用反射来创建对象,而避免使用new关键字来创建对象。但是上面这个类将这个字符串在类中写死了,如果将来想在类中换一个数据库,这个地方的代码还是需要进行修改。这个时候我们可以通过读取配置文件来获取要创建的对象的全限定类名的方式,使用配置文件将其配置进去,然后使用配置文件的方式来将其读取出来得到要读取对象的全限定类名,然后使用反射来创建对象。
(5)如下所示三层调用模型中,存在很强的耦合性,使得代码的独立性很差。
/**
* Dao类账户的持久层接口
*/
public interface AccountDao {
void saveAccount();
} import com.itheima.dao.AccountDao; /**
* 账户的持久层实现类
*/
public class AccountDaoImpl implements AccountDao {
public void saveAccount() {
System.out.println("AccountDao say hello world");
}
}
/**
* Service类业务层的接口,操作账户
*/
public interface AccountService {
void saveAccount();
} import com.itheima.dao.AccountDao;
import com.itheima.dao.impl.AccountDaoImpl;
import com.itheima.service.AccountService; /**
*
* 账户的业务层实现类
*/
public class AccountServiceImpl implements AccountService {
//下面通过new来创建对象的方式是我们应该避免的地方
private AccountDao accountDao = new AccountDaoImpl();
public void saveAccount() {
accountDao.saveAccount();
}
}
import com.itheima.service.AccountService;
import com.itheima.service.com.itheima.service.impl.AccountServiceImpl; /**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
public static void main(String[] args){
AccountService as = new AccountServiceImpl();
as.saveAccount();
}
}
上面这种通过New的方式来调用类,当某个类出错的时候,会在编译期报错,会使得类的独立性很差,耦合性很强。
(6)接下来我们通过工厂模式解耦
Dao层
package com.itheima.dao; /**
* 账户的持久层接口
*/
public interface AccountDao {
void saveAccount();
} //DaoService层
package com.itheima.dao.impl; import com.itheima.dao.AccountDao; /**
* 账户的持久层实现类
*/
public class AccountDaoImpl implements AccountDao {
public void saveAccount() {
System.out.println("AccountDao say hello world");
}
}
Service层
package com.itheima.service; /**
* 业务层的接口,操作账户
*/
public interface AccountService {
void saveAccount();
} package com.itheima.service.impl; import com.itheima.dao.AccountDao;
import com.itheima.dao.impl.AccountDaoImpl;
import com.itheima.factory.BeanFactory;
import com.itheima.service.AccountService; /**
*
* 账户的业务层实现类
*/
public class AccountServiceImpl implements AccountService {
//下面通过new来创建对象的方式是我们应该避免的地方
// private AccountDao accountDao = new AccountDaoImpl();
private AccountDao accountDao = (AccountDao) BeanFactory.getBean("accountDao");
public void saveAccount() {
accountDao.saveAccount();
}
}
//Client
package com.itheima.ui; import com.itheima.factory.BeanFactory;
import com.itheima.service.AccountService; /**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
public static void main(String[] args){
// AccountService as = new AccountServiceImpl();
AccountService as = (AccountService) BeanFactory.getBean("accountService");
as.saveAccount();
}
}
//工厂
package com.itheima.factory; import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; /**
* 创建Bean对象的工厂
* Bean在计算机英语中有可重用组件的含义
* JavaBean不等于实体类,JavaBean的范围要远大于实体类。是用Java语言编写的可重用组件
* 它就是创建Service和Dao对象的
* 第一个:需要一个配置文件来配置我们的 ServiceDao
* 配置文件的内容:全限定类名=唯一标志对应关系
* 第二个:通过读取配置文件中配置的内容,反射创建Bean对象
* 配置文件可以是xml,也可以是properties
*/
public class BeanFactory {
//定义一个Peoperties对象
private static Properties props;
//使用静态代码块为Properties对象赋值
static {
try {
//实例化对象
props= new Properties();
//获取Properties文件的流对象
InputStream in =BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
} catch (IOException e) {
throw new ExceptionInInitializerError("初始化properties失败");
}
} /**
* 根据bean的名称获取bean对象
* @return
*/
public static Object getBean(String beanName){
Object bean =null;
try {
String beanPath = props.getProperty(beanName);
bean = Class.forName(beanPath).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return bean;
}
}
//Bean.properties
accountService=com.itheima.service.impl.AccountServiceImpl
accountDao=com.itheima.dao.impl.AccountDaoImpl
Spring的基本应用(1):依赖以及控制反转的更多相关文章
- Helloworld之Spring依赖注入/控制反转(DI/IoC)版
Helloworld之Spring依赖注入/控制反转(DI/IoC)版 作者:雨水, 日期:2014-10-29 摘要:本文主要用于培训刚開始学习的人理解Spring中的依赖注入的基本概念. 先介绍依 ...
- Spring的三大核心思想:IOC(控制反转),DI(依赖注入),AOP(面向切面编程)
Spring核心思想,IoC与DI详解(如果还不明白,放弃java吧) 1.IoC是什么? IoC(Inversion of Control)控制反转,IoC是一种新的Java编程模式,目前很多 ...
- C#依赖注入控制反转IOC实现详解
原文:C#依赖注入控制反转IOC实现详解 IOC的基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器负责将这些联系在一起. ...
- PHP关于依赖注入(控制反转)的解释和例子说明
PHP关于依赖注入(控制反转)的解释和例子说明 发表于2年前(2014-03-20 10:12) 阅读(726) | 评论(1) 8人收藏此文章, 我要收藏 赞2 阿里云双11绽放在即 1111 ...
- Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转
原文地址:http://blog.csdn.net/wangyang1354/article/details/50757098 我们经常会遇到这样一种情景,就是在我们开发项目的时候经常会在一个类中调用 ...
- Benefits of Using the Spring Framework Dependency Injection 依赖注入 控制反转
小结: 1. Dependency Injection is merely one concrete example of Inversion of Control. 依赖注入是仅仅是控制反转的一个具 ...
- Spring框架学习笔记(1)——控制反转IOC与依赖注入DI
Spring框架的主要作用,就是提供了一个容器,使用该容器就可以创建并管理对象.比如说Dao类等,又或者是具有多依赖关系的类(Student类中包含有Teacher类的成员变量) Spring有两个核 ...
- spring三大核心学习(一)---控制反转
记得当年大学时候,java的企业级框架还是ssh的天下(spring,struts和hibernate),但是现在,感觉spring已经完全把那两个框架甩在后边了.用spring的人越来越多,用str ...
- Spring详解(二)------IOC控制反转
我相信提到 Spring,很多人会脱口而出IOC(控制反转).DI(依赖注入).AOP等等概念,这些概念也是面试官经常问到的知识点.那么这篇博客我们就来详细的讲解 IOC控制反转. ps:本篇博客源码 ...
- laravel5.2总结--服务容器(依赖注入,控制反转)
1.依赖 我们定义两个类:class Supperman 和 class Power,现在我们要使用Supperman ,而Supperman 依赖了Power class Supperman { p ...
随机推荐
- HearthBuddy的狂野和休闲模式来回切换
表现1 配置是标准,休闲模式 然后一直重复提示 select desire deck select causal mode 表现2 配置是狂野,休闲模式 然后一直提示 切换到狂野 切换到标准 把模式切 ...
- idea出现灰色或者黄色的波浪线如何去除
1.File--setting--Editor-Inspections-Geneal-Duplicated Code 去除 主要是类中出现太多的重复代码,idea自动提示.
- 阶段3 3.SpringMVC·_06.异常处理及拦截器_6 SpringMVC拦截器之拦截器入门代码
创建拦截器 新建包 实现拦截器的接口 接口中没有强制实现里面的方法.jdk1.8的特性.接口中已经实现了方法 这就是相当于实现了这个接口.方法已经全帮你实现过了. 如果想去写新的实现方法.Ctrl+o ...
- bazel编译im2txt的问题
问题: 原本可以正常运行的程序,出现找不到tensorflow的问题.打印出来sys.version和sys.path,发现python版本并不是conda环境的版本 (tensorflow) yua ...
- 安装VMTool
一. 安装VMTool 开启虚拟机,然后在VMware上选虚拟机->安装VMTool 如果提示光驱被占用就先用root登录 在命令行中挂载光盘 #mount /dev/cdrom ...
- React-Native传值方式之 :DeviceEventEmitter添加监听控制并传值到其他页面
在 native 开发中,我们可以使用广播实现事件的订阅和事件的触发,从而实现不在该页面但是可以调用该页面的方法. 在 React Native 中,我们也可以使用 DeviceEventEmitte ...
- 网页设计——HTML(3)布局基础
为什么要布局? 网页布局,也就是如何安排网页的内容. 一个好的网页布局能够使人眼前一亮,吸引流量. 本篇文章中我们不讨论相关的设计理论,我们只对布局所用到的HTML知识进行学习. 几种简单的布局方式 ...
- 关于Typescript - HTMLElement上使用append / prepend函数的问题
因最近在做浏览器打印界面水印的问题,用到后台动态创建标签,样式的处理用到了append,prend函数,Angular build打包的时候却抛出了异常↓ ERROR in src/app/route ...
- 10分钟学会web通讯的四种方式,短轮询、长轮询(comet)、长连接(SSE)、WebSocket
一般看到标题我们一般会产生下面几个问题??? 什么是短轮询? 什么是长轮询? 长连接又是什么? wensocket怎么实现呢? 他们都能实现web通讯,区别在哪呢,哪个好用呢? 接下来我们就一个个来了 ...
- mysql大数据量插入参考
Mysql 千万数据10秒批量插入只需三步第一步:配置my.ini文件文件中配置bulk_insert_buffer_size=120M 或者更大将insert语句的长度设为最大.Max_allowe ...