前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站点击跳转浏览。
解耦 降低程序之间的耦合性
为什么要降低程序之间的耦合性
**原因很简单。当耦合度很高时,在代码维护过程中修改一个地方会涉及到很多地方。如果耦合关系不是澄清修改期间,后果可能是灾难性的,特别是对于有许多变化的项目需求和多人协作开发和维护,修改一个地方会导致模块的错误一直运行稳定,如果是严重的,将导致一个恶性循环,问题永远不能完全解决,开发和测试正与各种各样的问题作斗争。最终会导致项目延迟,降低用户满意度,增加成本。而且也提高了程序的复用性
引入类之间的耦合性
在我们学习jdbc访问数据库时,具体流程是
首先在maven里面导入依赖
<packaging>jar</packaging> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies>
然后就是jdbc的实现过程:
1.注册驱动
2.获取连接
3.获取操作数据库的预处理对象
4.执行SQL,得到结果集
5.遍历结果集
6.释放资源
具体代码如下:
public class Jdbc { 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/test","root","1234"); //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(); } }
第一种创建驱动方式
进行分析,上面代码中被注释的那句代码
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
如果把pom里面的依赖注释就相当于没有jar包,然后我们进行编译
则不能编译,会是一个错误,如图所示:
第二种创建驱动方式
Class.forName(“com.mysql.jdbc.Driver”);
这句代码就只依赖于一个字符串而不是一个驱动类。
这样子当jar包不存在时,就是一个异常而不是一个错误。这样子就是避免的类之间的耦合性
但是产生一个新的问题,导致这个字符串在类中写死了如果换成其他数据库的话,就还要改代码,所以我们要通过配置文件来获取要创建的对象全限定类名,然后再用反射来创建对象
所以 解耦的思路:
第一步:使用反射来创建对象,而避免使用new关键字。
第二步:通过读取配置文件来获取要创建的对象全限定类名
实际开发中:
应该做到:编译期不依赖,运行时才依赖。
业务层Service调用持久层Dao时的耦合性
Dao层
userdao层的接口
public interface IUserDao { void save(); }
userdao层的实现类
package Dao.IMPL; import Dao.IUserDao; public class UserDao implements IUserDao { public void save() { System.out.println("hello"); } }
UserService的接口
package Service; public interface IUserService { void save(); }
UserService的实现类
package Service.IMPL; import Dao.IMPL.UserDao; import Service.IUserService; public class UserService implements IUserService { //private将这个对象私有化 //因为dao是一个接口的实现类 接口是不是实例化的 但是可以创建一个接口的实现类对象 private IUserDaodao=new UserDao(); public void save() { System.out.println("hello"); } }
private IUserDaodao=new UserDao(); 这句代码就是Service层调用Dao层,当我们把UserDao的代码去除之后,程序就出现报错,不能编译成功,说明程序之间的耦合性太强了。
工厂模式解耦合
上面的service层调用dao层的耦合性太强之后我们可以参考之前的jdbc里面的步骤。
第一步:使用反射来创建对象,而避免使用new关键字。 第二步:通过读取配置文件来获取要创建的对象全限定类名
所以我们可以通过工厂来进行一个解耦
BeanFactory:个创建Bean对象的工厂
什么是Bean
在计算机英语中,有可重用组件的含义,可重用的意思是一个servlet可能有多个service 一个service中可能有多个dao.一个servicc或者一个dao都是一个Bean
第一步:需要一个配置文件来配置我们的service和dao 配置的内容:唯一标识=全限定类名(key=value)
我们创建一个Bean.properties也可以是一个Bean.xml,在这里我们在resources里面创建一个Bean.properties记录里面的全限定类名
UserService=Service.IMPL.UserService UserDao=Dao.IMPL.UserDao
第二步通过读取配置文件中配置的内容,反射创建对象
package factory; import java.io.InputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class BeanFactory { //读取配置文件 //定义一个静态Properties对象 private static Properties props; // //定义一个Map,用于存放我们要创建的对象。我们把它称之为容器 //多例变单例 private static Map<String,Object> beans; //使用静态代码块为Properties对象赋值 static { try { //实例化对象 props = new Properties(); //获取properties文件的流对象 //这个时候不能用new FileInputStream因为这这个时候的相对路肩和绝对路径都不管用 //we工程部署src没有了 相对路径不能用 绝对路径也不行 //要用类加载器来进行操作 InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); //加载一个流对象 props.load(in); // //实例化容器 beans = new HashMap<String,Object>(); // //取出配置文件中所有的Key Enumeration keys = props.keys(); // //遍历枚举 while (keys.hasMoreElements()){ // //取出每个Key String key = keys.nextElement().toString(); // //根据key获取value String beanPath = props.getProperty(key); // //反射创建对象 Object value = Class.forName(beanPath).newInstance(); // //把key和value存入容器中 beans.put(key,value); } }catch(Exception e){ //抛出一个初始化错误 后面直接执行不了 throw new ExceptionInInitializerError("初始化properties失败!"); } } /** * 根据bean的名称获取对象 用Object类型做返回值 * @param beanName * @return */ public static Object getBean(String beanName){ return beans.get(beanName);
这样之后,我们再调用dao层时就可以把在BeanFactory里面创建
private IUserDao dao= (IUserDao) BeanFactory.getBean("UserDao");
同样调用service代码也发生变化
IUserService service= (IUserService) BeanFactory.getBean("UserService");
这样之后,再把删除就只报异常,而且如果需要更改代码里面的值,我们就只用更改配置文件里面的代码这样就可以更加快速的进行更改操作。