1、聊聊解耦?
耦合:代碼之間的關聯關系稱為耦合,具有強關聯關系的稱為強耦合,
解耦:解除代碼之間的關聯關系,使每個業務代碼職責單一,目的明確,通常我們在業務上稱為解耦,
2、代碼示例
我們以傳統的EJB開發模式為例子,先不以框架展示,大家可以看看一些改代碼難受的場景,
業務來了:我需要把一段資料保存到mysql資料庫中,按照分層邏輯實作(controller,service,dao)
Dao介面層:
public interface UserDao { /** * 保存的介面方法 */ void save(); }Dao的mysql實作:
public class UserDaoMysqlImpl implements UserDao { @Override 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(); @Override 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 { @Override 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(); @Override public void save() { userDao.save(); } }我們發現,在目前的需求形式上,dao的擴展我們是一定會需要改的,因為滿足多型的特性,但是我們增加一個dao層的某個業務,連service業務層代碼也要動,你想想,如果業務層代碼達到了上千,即便你有了注釋,改了某一層,另一層也要跟著改動,是不是很難受?
所以我們目前要解決:(如果每次dao進行擴展都去service修改原始碼來切換到新的dao,這樣做法耦合度太高,每次都需要去修改UserServiceImpl的代碼)
這個場景,我們很經典的稱為耦合!!!!我們可以自己給耦合多一個定義
耦合:代碼之間的關聯關系稱為耦合,更具體的說,在當前主流的職責劃分層次(controller,service,dao)明確的前提下進行編碼,某一層的改動,會導致另一個層跟著變動,可以稱為耦合,
3、工廠模式可以解耦
在不了解工廠模式的前提下,就默認把這個作為生產物件的地方;
我們新建一個工廠,稱為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(); @Override 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的思路
覺得還可以,先收藏下唄,我會持續更新思想和程序,到原始碼的!!!!
最后一句話,解耦不代表代碼一定少,更多時候是你用更多的代碼來解決人力成本,所以新手一定要記得,解耦的原則,是減少開發中出現的問題,增加開發效率,不代表代碼一定會減少下去,希望不要有這樣的誤區!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/260035.html
標籤:java
