使用工厂模式解耦

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 耦合:程序间的依赖关系耦合包括:1. 类与类之间的依赖关系2. 方法与方法之间的依赖关系

耦合

耦合:程序间的依赖关系

耦合包括:

  1. 类与类之间的依赖关系
  2. 方法与方法之间的依赖关系

解耦

解耦:降低程序间的依赖关系

一、由JDBC引出解耦

先上一段熟悉的jdbc代码

       //1.导入驱动jar包

       //2.注册驱动

       DriverManager.registerDriver(newcom.mysql.jdbc.Driver());

       //3.获取数据库连接对象

       Connectionconn=DriverManager.getConnection("jdbc:mysql://localhost:3306/contest?useUnicode=true&characterEncoding=UTF-8", "user", "password");

       //4.定义SQL语句

       Stringsql="update hello set age=30 where id=1";

       //5.获取执行SQL的对象Statement

       Statementstmt=conn.createStatement();

       //6.执行SQL

       intresult=stmt.executeUpdate(sql);

       //7.处理结果

       System.out.println(result);

       //8.释放资源

       stmt.close();

       conn.close();

显然,当我们不导入mysql的驱动jar包,这段代码在编译期就会报错,因为我们用到了com.mysql.jdbc.Driver(),会导致类的独立性很差。如何解决上诉问题?

Class.forName("com.mysql.jdbc.Driver");

我们常常使用上诉代码来加载驱动,这样编译期不再依赖于某个具体的驱动类,而依赖一个字符串。查看com.mysql.jdbc.Driver类的源码发现静态代码块(当类被加载进内存,静态代码块会自动执行)

static {

       try {

           DriverManager.registerDriver(newDriver());

       } catch (SQLExceptionvar1) {

           thrownewRuntimeException("Can't register driver!");

       }

   }

可知,Class.forName("com.mysql.jdbc.Driver");本质上还是DriverManager.registerDriver(Driver driver),但这样封装一下,不仅提高了代码的独立性(不导jar包,编译期不报错,运行时会报错),而且简化了代码。

我们知道字符串在代码中是写死的,当我们想要更换为其他数据库的驱动时,还要更改代码,十分不便。如何解决上诉问题?

jdbc.properties

url=jdbc:mysql:///contest

user=xxx

password=xxx

driver=com.mysql.jdbc.Driver

我们可以通过读取配置文件来获取需要的数据

           //1.创建properties集合类

           Propertiespro=newProperties();

           //获取src目录下文件的方式--> ClassLoader 类加载器(可以加载字节码文件进内存,并且可以获取src目录下资源的路径)

           ClassLoaderclassLoader=JDBCUtils.class.getClassLoader();

           URLres=classLoader.getResource("jdbc.properties");

           Stringpath=res.getPath();

           //2.加载文件

           pro.load(newFileReader(path));

           //3.获取数据,并赋值

           url=pro.getProperty("url");

           user=pro.getProperty("user");

           password=pro.getProperty("password");

           driver=pro.getProperty("driver");

           //4.注册驱动

           Class.forName(driver);


综上操作,可以实现编译期不依赖某个类,运行时才依赖,降低了类与类之间的依赖关系,实现了解耦

解耦的思路

  1. 使用反射来创建对象,而避免使用new关键字
  2. 通过读取配置文件来获取要创建的对象的全限定类名

二、将解耦思想运用到三层架构

三层架构

因为面向接口编程,所以三层架构的每一层我们都写了一个接口,在impl包写实现类,使用的是实现类对象

步骤1:创建持久层接口

packagecn.upeveryday.dao;

/**

* 账户的持久层接口

*/

publicinterfaceIAccountDao {

   voidsaveAccount();

}

步骤2:创建持久层实现类

packagecn.upeveryday.dao.impl;

importcn.upeveryday.dao.IAccountDao;

/**

* 账户的持久层实现类

*/

publicclassAccountDaoImplimplementsIAccountDao {

   publicvoidsaveAccount() {

       System.out.println("保存成功!");

   }

}

步骤3:创建业务层接口

packagecn.upeveryday.service;

/**

* 账户的业务层接口

*/

publicinterfaceIAccountService {

   /**

    * 模拟保存

    */

   voidsaveAccount();

}

步骤4:创建业务层实现类

packagecn.upeveryday.service.impl;

importcn.upeveryday.dao.IAccountDao;

importcn.upeveryday.service.IAccountService;

/**

* 账户的业务层实现类

*/

publicclassAccountServiceImplimplementsIAccountService {

   //业务层调用持久层

   privateIAccountDaoaccountDao=newAccountDaoImpl();

   publicvoidsaveAccount() {

       accountDao.saveAccount();

   }

}

步骤5:创建表现层

packagecn.upeveryday.ui;

importcn.upeveryday.factory.BeanFactory01;

importcn.upeveryday.factory.BeanFactory02;

importcn.upeveryday.service.IAccountService;

/**

* 模拟一个表现层,用于调用业务层

*/

publicclassClient {

   publicstaticvoidmain(String[] args) {

       AccountServiceImplservice=newAccountServiceImpl();

       service.saveAccount();

   }

}

三层架构解耦分析

我们知道,在三层架构中业务层调用持久层,表现层调用业务层

由解耦思路:

  1. 使用反射来创建对象,而避免使用new关键字
  2. 通过读取配置文件来获取要创建的对象的全限定类名

可以使用工厂模式解耦

三、工厂模式解耦

/**

* 一个创建Bean对象的工厂

* Bean:在计算机英语中,是可重用组件的意思

*      可重用组件:业务层、持久层都是可重用组件(表现层调用业务层,业务层调用持久层)

* javabean:用java语言编写的可重用组件

*      javabean范围 > 实体类范围

* BeanFactory就是用来创建service和dao对象的:

* 1.需要一个配置文件来配置我们的service和dao(配置文件可以是xml或properties)

*      配置的内容:唯一标识符=全限定类名(key=value)

* 2.读取配置文件内容,反射创建对象

*      配置文件可以是xml,也可以是properties

*/

单例:从始至终只有一个实例对象。例如:servlet

多例:有多个对象

如果是多例的,对象会被创建多次,类中的成员变量每次都会被初始化,因此不存在线程安全问题

单例,对象只被创建一次,类中的成员变量也只被初始化一次,则会产生线程安全问题

对象被创建多次,执行效率没有单例对象高。而且我们在service和dao中并没有定义成员变量,因此不存在线程安全问题

工厂模式实现了由自己控制资源转变为工厂factory控制资源,从而实现控制反转IOC(Inversion of Control),解决了程序间的依赖关系,spring是使用配置的方式实现工厂模式进而实现解耦,而不需要我们自己编写beanFactory代码

IOC只能解决程序间的依赖关系


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
0
0
0
3
分享
相关文章
一文了解IntelliJ IDEA如何使用git上传代码到GitHub(附常见问题解决方案)
一文了解IntelliJ IDEA如何使用git上传代码到GitHub(附常见问题解决方案)
596 0
解决File.delete()删除不掉文件
首先注意两点: 此文件被使用的时候无法删除(比如网络输出没关闭流) 判断此文件是否存在再做删除(exists) 删除文件夹之前先删除文件夹下的所有文件(递归解决) 判断是否删除成功会有返回值,文件名错了的话,删除文件不会报错。
2399 0
Mybatis-Plus实现Service封装
Mybatis-Plus实现Service封装
326 1
IDEA常用配置之代码自动格式化删除无用导入
IDEA常用配置之代码自动格式化删除无用导入
554 1
MyBatis 常见错误
为初学者准备的常见MyBatis 异常汇总 ,持续完善中
2823 0
Idea创建SpringBoot多模块项目
我们可以定义一个维度,以此来划分模块,例如上述商城、可以划分成商品、库存和订单模块。也可以目录结构分层,`Controller`层,只不过没人这样做。这样就引申出了下一个问题`拆分策略`。
1129 0
Idea创建SpringBoot多模块项目
eNSP常用命令 华为模拟器eNSP常用命令
路由器常用命令:进入任务视图给路由器取名,进入指定接口,给当前路由器接口配置IP地址和子网掩码,退出接口或系统视图,启用DHCP,指定该接口拥有DHCP功能,指定DNS服务器的IP地址,显示全部ip的路由表,显示指定ip路由表,添加静态路由。交换机常用命令:交换机改变语言模式,创建vlan,查看所有vlan,将接口拆分为多个子接口,指定接口与哪个vlan关联,启用arp广播,将接口修改为access接口,将接口修改为trunk接口,将接口划分到指定vlan里,查看开启stp后的交换机接口的接口情况,查看交换
1428 0
eNSP常用命令 华为模拟器eNSP常用命令
华为ensp模拟器 三层交换机
先用vlan把用户隔离开,再用三层交换机,将隔离的用户连起来。隔离:隔离的是故障连通:连通的是正常通信运用三层交换机实现。用LSW2交换机将两台pc机隔开,划分到不同的vlan里。再用LSW1交换机将两台pc机连接。这样两台pc机就不能直接通过LSW2交换机通信(隔离病毒的传播),而是需要通过LSW1这个交换机实现通信(实现通信)。 2、将连接pc机的接口设置为access接口(设置前要进入该接口 int命令) 3、将接口划分进入vlan里(设置前要进入该接口) 4、将连接另一台交换机的
华为ensp模拟器 三层交换机
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问