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

一、程序的耦合和解耦

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. Qt第三方库libvlc-qt——ubuntu上编译、安装,测试

      cmake 3.0编译安装(最低版本要求): sudo apt-get install ncurses-dev sudo apt-get install build-essential 下载cma ...

  2. 只需体验三分钟,你就会跟我一样,爱上这款Toast

    只需体验三分钟,你就会跟我一样,爱上这款Toast https://www.jianshu.com/p/9b174ee2c571

  3. LC 954. Array of Doubled Pairs

    Given an array of integers A with even length, return true if and only if it is possible to reorder ...

  4. 阶段3 3.SpringMVC·_06.异常处理及拦截器_5 SpringMVC拦截器之编写controller

    先新建包,com.itcast.controller,然后把异常拦截的项目的UserController复制过来. 复制过来稍作修改 创建pages文件件,然后新建success.jsp页面 部署当前 ...

  5. 通过TCODE查找SPRO路径

    1.SE11:CUS_ACTOBJ,根据OBJECTNAME(对象名称),即视图名称,获取Customizing activity(ACT_ID) 2.根据ACT_ID在表CUS_IMGACT获取说明 ...

  6. SOA简介

    1.你可以把SOA理解为一种概念,总的来说就是面向服务的设计. 这个概念简单来理解就是把之前所谓的模块划分做成服务. 比如之前的日志模块,需要引用你的dll,调用你的写日志方法来写日志.这样当有多个系 ...

  7. Xcode8.1 真机测试 ,添加iOS10.3的idk到Xcode8.1中

    1.下载iOS10.3的idk包; 2.解压, 找到路径 Finder -> 应用程序 -> 右键Xcode -> 显示包内容 -> Contents -> Develo ...

  8. Ubuntu16.04系统Tensorflow源码安装

    最近学习Tensorflow,记录一下安装过程.目前安装的是CPU版的 1.下载tensorflow源码 tensorflow是个开源库,在github上有源码,直接在上面下载.下载地址:https: ...

  9. 微信小程序页面左右滑动事件

    微信小程序提供了页面的上下滚动的事件,在页面的js文件中, page({ onPageScroll(e) { console.log(e.scrollTop) } }) 但是不是滑动事件,滑动事件需要 ...

  10. 对于MVVM的理解

    MVVM 是Model-View-ViewModel的缩写. Model 代表数据模型,也可以在model中定义数据修改和操作的业务逻辑. View 代表UI组件,负责姜黄素局模型转化成UI展现出来. ...