一、聊聊解耦?
耦合:代码之间的关联关系称为耦合,具备强关联关系的称为强耦合。mysql
解耦:解除代码之间的关联关系,使每一个业务代码职责单一,目的明确,一般咱们在业务上称为解耦。spring
二、代码示例
咱们以传统的EJB开发模式为例子,先不以框架展现,你们能够看看一些改代码难受的场景。sql
业务来了:我须要把一段数据保存到mysql数据库中,按照分层逻辑实现(controller,service,dao)数据库
Dao接口层:oracle
public interface UserDao {app
/**框架
* 保存的接口方法ide
*/sqlserver
void save();编码
}
Dao的mysql实现:
public class UserDaoMysqlImpl implements UserDao {
public void save() {
System.out.println("保存mysql数据库成功!");
}
}
Service接口层:
public interface UserService {
/**
* 业务接口保存方法
*/
void save();
}
Service的实现:
public class UserServiceImpl implements UserService {
//业务层调用数据dao层,这里不解释了
private UserDao userDao = new UserDaoMysqlImpl();
public void save() {
userDao.save();
}
}
Controller视图层:
public class UserController {
private UserService userService = new UserServiceImpl();
public void save(){
userService.save();
}
}
很明显,咱们已经实现了业务功能:保存一段数据进mysql数据库
这个时候,你的产品经理说,客户mysql坏了,刚装了个oracle,你再改改吧?
而后你这个时候也就加个oracle,实际上不费时,需求咱们再补充下
如今需求:保存一段数据,能够保存在mysql,也能够保存在oracle
上面已经有mysql代码了,咱们能够知道,我须要增长个dao的实现,称为UserDaoOracleImpl
上代码先:
public class UserDaoOracleImpl implements UserDao {
public void save() {
System.out.println("保存oracle数据库成功!");
}
}
ok咱们还要改一个地方,就是UserServiceImpl,以前父类接口指向的子类引用要改为oracle
public class UserServiceImpl implements UserService {
//业务层调用数据dao层,这里不解释了
// private UserDao userDao = new UserDaoMysqlImpl();
private UserDao userDao = new UserDaoOracleImpl();
public void save() {
userDao.save();
}
}
咱们发现,在目前的需求形式上,dao的扩展咱们是必定会须要改的,由于知足多态的特性,可是咱们增长一个dao层的某个业务,连service业务层代码也要动,你想一想,若是业务层代码达到了上千,即使你有了注释,改了某一层,另外一层也要跟着改动,是否是很难受?
因此咱们目前要解决:(若是每次dao进行扩展都去service修改源码来切换到新的dao,这样作法耦合度过高,每次都须要去修改UserServiceImpl的代码)
这个场景,咱们很经典的称为耦合!!!!咱们能够本身给耦合多一个定义
耦合:代码之间的关联关系称为耦合,更具体的说,在当前主流的职责划分层次(controller,service,dao)明确的前提下进行编码,某一层的改动,会致使另外一个层跟着变更,能够称为耦合。
三、工厂模式能够解耦
在不了解工厂模式的前提下,就默认把这个做为生产对象的地方;
咱们新建一个工厂,称为BeanFactory
/**
* 定义一个bean工厂,专门生产普通对象
*/
public class BeanFactory {
public static UserDao getBean() {
return new UserDaoMysqlImpl();
}
}
而后咱们要对耦合的那一层修改,目前看是把service解耦了吧?我全部建立对象的操做,都在一个具体的工厂类里;
public class UserServiceImpl implements UserService {
//业务层调用数据dao层,这里不解释了
// private UserDao userDao = new UserDaoMysqlImpl();
// private UserDao userDao = new UserDaoOracleImpl();
private UserDao userDao = BeanFactory.getBean();
public void save() {
userDao.save();
}
}
很明显,我已经进行了service和dao解耦;可是!!!!!!
该死的需求是:我要改为oracle,sqlserver,......
那咱们继续:我顺便把以前的getBean换成了mysql的
public class UserServiceImpl implements UserService {
//业务层调用数据dao层,这里不解释了
// private UserDao userDao = new UserDaoMysqlImpl();
// private UserDao userDao = new UserDaoOracleImpl();
// private UserDao userDao = BeanFactory.getMysqlBean();
private UserDao userDao = BeanFactory.getOracleBean();
@Override
public void save() {
userDao.save();
}
}
很明显我如今已经把dao和service的耦合,转移到了工厂和service上了,这就是解耦的一步;可是你们仍是疑惑,我感受我代码增多了?或者更麻烦了?咱们继续看
咱们每次增长新的业务,扩展,都要修改工厂,因此这个咱们能够不能够不在代码里直接作这个事情?--------引出配置文件
咱们在resources下定义一个applicationContext.properties
userDao=com.chenxin.gmall.user.demo.dao.UserDaoMysqlImpl
userService=com.chenxin.gmall.user.demo.service.UserServiceImpl
若是咱们须要换成oracle,咱们只改这个配置文件,改为UserDaoOracleImpl,不须要去动代码
那咱们刚刚的BeanFactory就又能够经过读取配置文件的方式,用反射来建立对象,反射建立对象是根据对象的全类名作的,不是直接new,看看效果
/**
* 定义一个bean工厂,专门生产普通对象
*/
public class BeanFactory {
private static Properties properties = new Properties();
//1.加载配置文件
static {
InputStream resourceAsStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
try {
properties.load(resourceAsStream);
resourceAsStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// public static UserDao getMysqlBean() {
// return new UserDaoMysqlImpl();
// }
//
// public static UserDao getOracleBean() {
// return new UserDaoOracleImpl();
// }
public static UserDao getBean(String key){
// 2.使用key得到value
String className = properties.getProperty(key);
// 3.使用value利用反射技术建立对象
try{
return (UserDao) Class.forName(className).newInstance();
}catch(Exception e){
e.printStackTrace();
return null;
}
}
}
好了,咱们来需求,咱们要保存到oracle,sqlserver数据库,看看你是否是只须要多一个dao的oracle实现,而后去改配置文件就ok?多一个sqlserver后,改下applicationContext.properties
算了我直接写个代码吧:
/**
* 新增了sqlserver的支持,多态的表现
*/
public class UserDaoSqlServerImpl implements UserDao {
@Override
public void save() {
System.out.println("保存SqlServer数据库成功!");
}
}
改下applicationContext.properties
userDao=com.chenxin.gmall.user.demo.dao.UserDaoSqlServerImpl
userService=com.chenxin.gmall.user.demo.service.UserServiceImpl
你能够试一下,是否是这么干的!
如今看来,是解耦了很多吧。可是会有人发现吗,这个getBean返回值,是UserDao,若是你有不少,是否是咱们要写不少不少的Dao的getBean?别急,后面一步一步带你走向spring的思路
最后一句话,解耦不表明代码必定少,更多时候是你用更多的代码来解决人力成本,因此新手必定要记得,解耦的原则,是减小开发中出现的问题,增长开发效率,不表明代码必定会减小下去,但愿不要有这样的误区!
感谢阅读,三连是最大的支持!