推薦學習:
這可能是全網Java學習路線最完整,最詳細的版本了,沒有之一
1、聊聊解耦?
耦合:代碼之間的關聯關系稱為耦合,具有強關聯關系的稱為強耦合。
解耦:解除代碼之間的關聯關系,使每個業務代碼職責單一,目的明確,通常我們在業務上稱為解耦。
2、代碼示例
我們以傳統的EJB開發模式為例子,先不以框架展示,大家可以看看一些改代碼難受的場景。
業務來了:我需要把一段數據保存到mysql數據庫中,按照分層邏輯實現(controller,service,dao)
Dao接口層:
publicinterfaceUserDao{
/**
* 保存的接口方法
*/
voidsave();
}
Dao的mysql實現:
publicclassUserDaoMysqlImplimplementsUserDao{
@Override
publicvoidsave() {
System.out.println("保存mysql數據庫成功!");
}
}
Service接口層:
publicinterfaceUserService{
/**
* 業務接口保存方法
*/
voidsave();
}
Service的實現:
publicclassUserServiceImplimplementsUserService{
//業務層調用數據dao層,這里不解釋了
privateUserDao userDao =newUserDaoMysqlImpl();
@Override
publicvoidsave() {
userDao.save();
}
}
Controller視圖層:
publicclassUserController{
privateUserService userService =newUserServiceImpl();
publicvoidsave(){
userService.save();
}
}
很明顯,我們已經實現了業務功能:保存一段數據進mysql數據庫
這個時候,你的產品經理說,客戶mysql壞了,剛裝了個oracle,你再改改吧?
然后你這個時候也就加個oracle,實際上不費時,需求我們再補充下
現在需求:保存一段數據,可以保存在mysql,也可以保存在oracle
上面已經有mysql代碼了,我們可以知道,我需要增加個dao的實現,稱為UserDaoOracleImpl
上代碼先:
publicclassUserDaoOracleImplimplementsUserDao{
@Override
publicvoidsave() {
System.out.println("保存oracle數據庫成功!");
}
}
ok我們還要改一個地方,就是UserServiceImpl,之前父類接口指向的子類引用要改成oracle
publicclassUserServiceImplimplementsUserService{
//業務層調用數據dao層,這里不解釋了
// private UserDao userDao = new UserDaoMysqlImpl();
privateUserDao userDao =newUserDaoOracleImpl();
@Override
publicvoidsave() {
userDao.save();
}
}
我們發現,在目前的需求形式上,dao的擴展我們是一定會需要改的,因為滿足多態的特性,但是我們增加一個dao層的某個業務,連service業務層代碼也要動,你想想,如果業務層代碼達到了上千,即便你有了注釋,改了某一層,另一層也要跟著改動,是不是很難受?
所以我們目前要解決:(如果每次dao進行擴展都去service修改源碼來切換到新的dao,這樣做法耦合度太高,每次都需要去修改UserServiceImpl的代碼)
這個場景,我們很經典的稱為耦合!!!!我們可以自己給耦合多一個定義
耦合:代碼之間的關聯關系稱為耦合,更具體的說,在當前主流的職責劃分層次(controller,service,dao)明確的前提下進行編碼,某一層的改動,會導致另一個層跟著變動,可以稱為耦合。
3、工廠模式可以解耦
在不了解工廠模式的前提下,就默認把這個作為生產對象的地方;
我們新建一個工廠,稱為BeanFactory
/**
* 定義一個bean工廠,專門生產普通對象
*/
publicclassBeanFactory{
publicstaticUserDaogetBean() {
returnnewUserDaoMysqlImpl();
}
}
然后我們要對耦合的那一層修改,目前看是把service解耦了吧?我所有創建對象的操作,都在一個具體的工廠類里;
publicclassUserServiceImplimplementsUserService{
//業務層調用數據dao層,這里不解釋了
// private UserDao userDao = new UserDaoMysqlImpl();
// private UserDao userDao = new UserDaoOracleImpl();
privateUserDao userDao = BeanFactory.getBean();
@Override
publicvoidsave() {
userDao.save();
}
}
很明顯,我已經進行了service和dao解耦;但是!!!!!!
該死的需求是:我要改成oracle,sqlserver,......
那我們繼續:我順便把之前的getBean換成了mysql的
publicclassUserServiceImplimplementsUserService{
//業務層調用數據dao層,這里不解釋了
// private UserDao userDao = new UserDaoMysqlImpl();
// private UserDao userDao = new UserDaoOracleImpl();
// private UserDao userDao = BeanFactory.getMysqlBean();
privateUserDao userDao = BeanFactory.getOracleBean();
@Override
publicvoidsave() {
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工廠,專門生產普通對象
*/
publicclassBeanFactory{
privatestaticProperties properties =newProperties();
//1.加載配置文件
static{
InputStream resourceAsStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
try{
properties.load(resourceAsStream);
resourceAsStream.close();
}catch(IOException e) {
e.printStackTrace();
}
}
//publicstaticUserDaogetMysqlBean() {
// return new UserDaoMysqlImpl();
// }
//
// public static UserDao getOracleBean() {
// return new UserDaoOracleImpl();
// }
publicstaticUserDaogetBean(String key){
// 2.使用key獲得value
String className = properties.getProperty(key);
// 3.使用value利用反射技術創建對象
try{
return(UserDao) Class.forName(className).newInstance();
}catch(Exception e){
e.printStackTrace();
returnnull;
}
}
}
好了,我們來需求,我們要保存到oracle,sqlserver數據庫,看看你是不是只需要多一個dao的oracle實現,然后去改配置文件就ok?多一個sqlserver后,改下applicationContext.properties
算了我直接寫個代碼吧:
/**
* 新增了sqlserver的支持,多態的表現
*/
publicclassUserDaoSqlServerImplimplementsUserDao{
@Override
publicvoidsave() {
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的思路
最后一句話,解耦不代表代碼一定少,更多時候是你用更多的代碼來解決人力成本,所以新手一定要記得,解耦的原則,是減少開發中出現的問題,增加開發效率,不代表代碼一定會減少下去,希望不要有這樣的誤區!
感謝閱讀,三連是最大的支持!
免責聲明:本文內容來自用戶上傳并發布,站點僅提供信息存儲空間服務,不擁有所有權,信息僅供參考之用。