一、聊聊解耦?
耦合:代碼之間的關聯關係稱爲耦合,具備強關聯關係的稱爲強耦合。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的思路
最後一句話,解耦不表明代碼必定少,更多時候是你用更多的代碼來解決人力成本,因此新手必定要記得,解耦的原則,是減小開發中出現的問題,增長開發效率,不表明代碼必定會減小下去,但願不要有這樣的誤區!
感謝閱讀,三連是最大的支持!