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

一、程序的耦合和解耦

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. HearthBuddy卡牌无法识别

    界面上无法识别,提示是 [Unidentified card ID :DAL_010][Unidentified card ID :DAL_415] Unidentified card ID :HER ...

  2. When Database Sharding is Appropriate DATABASE SHARDING

    w横切 http://www.agildata.com/database-sharding/ When Database Sharding is Appropriate Database Shardi ...

  3. MySQL——逻辑分层与存储引擎

    MySQL是最受欢迎的开源SQL数据库管理系统,由Oracle Corporation开发,分发和支持. MySQL网站(http://www.mysql.com/)提供有关MySQL软件的最新信息. ...

  4. 前端性能之Chrome的Waterfall

    浏览器根据HTML中外连资源出现的顺序,依次放入队列(队列),然后根据优先级确定向服务器获取资源的顺序.同优先级的资源根据HTML中出现的先后顺序来向服务器获取资源. 瀑布中各项内容的含义: 排队: ...

  5. Json+Ajax相关

    Ajax前戏之json: 1.什么是json? JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式. 2.json对象和JavaScript ...

  6. add_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'

    发送一个报头,告诉浏览器当前页面不进行缓存,每次访问的时间必须从服务器上读取最新的数据 一般情况下,浏览器为了加快浏览速度会对网页进行缓存,在一定时间内再次访问同一页面的时候会有缓存里面读取而不是从服 ...

  7. RxJava2实战---第七章 合并操作符和连接操作符

    RxJava2实战---第七章 合并操作符和连接操作符 RxJava的合并操作符: startWith():在数据序列的开头增加一项数据. merge:将多个Observable合并为一个. merg ...

  8. 利用java执行shell脚本

    BPMN中存在由系统执行的脚本任务,shell脚本任务也是该系统任务脚本中的一种,利用的也是由java执行shell脚本. 代码中的ProcessBuilder类,为java.lang.Process ...

  9. Python列表排序

    1.冒泡排序 冒泡排序(Bubble Sort)是一种简单的排序算法.它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.遍历数列的工作是重复地进行直到没有再需要交换,也就 ...

  10. 使用Keepalived实现Nginx高可用

    Keepalived是一个路由软件,可以提供linux系统和linux系统上的组件的负载均衡和高可用,高可用基于VRRP(Virtual Router Redundancy Protocol,虚ip) ...