在说到这里的时候,首先要说下程序的耦合和解耦,以便对上节做一个解释。

一、程序的耦合和解耦

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):依赖以及控制反转的更多相关文章

  1. Helloworld之Spring依赖注入/控制反转(DI/IoC)版

    Helloworld之Spring依赖注入/控制反转(DI/IoC)版 作者:雨水, 日期:2014-10-29 摘要:本文主要用于培训刚開始学习的人理解Spring中的依赖注入的基本概念. 先介绍依 ...

  2. Spring的三大核心思想:IOC(控制反转),DI(依赖注入),AOP(面向切面编程)

    Spring核心思想,IoC与DI详解(如果还不明白,放弃java吧) 1.IoC是什么?    IoC(Inversion of Control)控制反转,IoC是一种新的Java编程模式,目前很多 ...

  3. C#依赖注入控制反转IOC实现详解

    原文:C#依赖注入控制反转IOC实现详解 IOC的基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器负责将这些联系在一起. ...

  4. PHP关于依赖注入(控制反转)的解释和例子说明

    PHP关于依赖注入(控制反转)的解释和例子说明 发表于2年前(2014-03-20 10:12)   阅读(726) | 评论(1) 8人收藏此文章, 我要收藏 赞2 阿里云双11绽放在即 1111 ...

  5. Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转

    原文地址:http://blog.csdn.net/wangyang1354/article/details/50757098 我们经常会遇到这样一种情景,就是在我们开发项目的时候经常会在一个类中调用 ...

  6. Benefits of Using the Spring Framework Dependency Injection 依赖注入 控制反转

    小结: 1. Dependency Injection is merely one concrete example of Inversion of Control. 依赖注入是仅仅是控制反转的一个具 ...

  7. Spring框架学习笔记(1)——控制反转IOC与依赖注入DI

    Spring框架的主要作用,就是提供了一个容器,使用该容器就可以创建并管理对象.比如说Dao类等,又或者是具有多依赖关系的类(Student类中包含有Teacher类的成员变量) Spring有两个核 ...

  8. spring三大核心学习(一)---控制反转

    记得当年大学时候,java的企业级框架还是ssh的天下(spring,struts和hibernate),但是现在,感觉spring已经完全把那两个框架甩在后边了.用spring的人越来越多,用str ...

  9. Spring详解(二)------IOC控制反转

    我相信提到 Spring,很多人会脱口而出IOC(控制反转).DI(依赖注入).AOP等等概念,这些概念也是面试官经常问到的知识点.那么这篇博客我们就来详细的讲解 IOC控制反转. ps:本篇博客源码 ...

  10. laravel5.2总结--服务容器(依赖注入,控制反转)

    1.依赖 我们定义两个类:class Supperman 和 class Power,现在我们要使用Supperman ,而Supperman 依赖了Power class Supperman { p ...

随机推荐

  1. Nginx事件管理之epoll模块

    1. epoll 原理 假设有 100 万用户同时与一个进程保持着 TCP 连接,而每一时刻只有几十个或几百个 TCP 连接时活跃的(接收到 TCP 包),也就是说,在每一时刻,进程只需要处理这 10 ...

  2. LeetCode 145. 二叉树的后序遍历(Binary Tree Postorder Traversal)

    题目描述 给定一个二叉树,返回它的 后序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [3,2,1] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 解题思路 后 ...

  3. Python 图形界面元素

    from tkinter import * import os def button_click1(): try: filePath = r'D:\CloudMusic' os.system(&quo ...

  4. JS字符串转换为JSON的方法

    1.jQuery插件支持的转换方式:  示例: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符串转换成json对象 2.浏览 ...

  5. Linux自动输入密码登录用户

    每次进去Linux系统,都有切换root用户,输入密码很麻烦,所以就写了一个小脚本,自动输入密码,登录到root用户, 1,首先检查一些是否安装了expect root@wuzs:/home/wuzs ...

  6. JAVA和Tomcat运维整理

    安装JAVA和Tomcatapache-tomcat-8.5.37.tar.gz  jdk-8u191-linux-x64.rpm [root@localhost ~]# ll /usr/java/t ...

  7. 一张图搞懂Ajax原理

    本文整理在,我的github上.欢迎Star. 原理 说起ajax,就不得不说他背后的核心对象XMLHttpRequest,而说到XMLHttpRequest我觉得,从它的readyState状态说起 ...

  8. layui相关总结

    表格操作实例1: https://sun_zoro.gitee.io/layuitableplug/testTableCheckboxDisabled?v0.1.9

  9. SQL Server 收集数据库死锁信息

    背景 我们在数据库出现阻塞及时邮件预警提醒中监控了数据库的阻塞情况,为了更好的维护数据库,特别是提升终端客户用户体验,我们要尽量避免在数据库中出现死锁的情况.我们知道收集死锁可以开启跟踪标志如1204 ...

  10. Python简单网络爬虫实战—下载论文名称,作者信息(下)

    在Python简单网络爬虫实战—下载论文名称,作者信息(上)中,学会了get到网页内容以及在谷歌浏览器找到了需要提取的内容的数据结构,接下来记录我是如何找到所有author和title的 1.从sou ...