JAVA中OOAD(面向物件分析與設計依賴倒置原則)程式碼例項
阿新 • • 發佈:2018-11-10
簡介:什麼是依賴倒置原則?
軟體設計中,多層次之間相互依賴關係需要倒置為抽象類或介面,而不是直接依賴於具體的實現。 具體表現為: 1、上層模組不應該直接依賴下層實現,而應該依賴下層的抽象 2、每一個單獨的層次,抽象不應該依賴於細節,而細節應該依賴於抽象。
現在有一個使用者類UserBean我們要進行操作:(相當於將使用者資訊從頂層傳到服務層,再從服務層傳到底層,由底層邏輯具體去實現操作細節,這裡的規則是,介面層(頂層)呼叫服務層(業務層)介面,服務層呼叫底層(持久層,也稱資料訪問層)介面)
package com.work.test.bean; import java.io.Serializable; public class UserBean implements Serializable { private static final long serialVersionUID = -2243170754006229032L; private Long id;//使用者id private String userName;//使用者姓名 public UserBean() { super(); // TODO Auto-generated constructor stub } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @Override //複寫toString方法 public String toString() { return "UserBean [id=" + id + ", userName=" + userName + "]"; } }
程式碼例項:
底層(持久層,也稱資料訪問層,主要實現細節邏輯,具體的操作)
介面程式碼
IUserDao介面定義:
package com.work.test.reverse;
import com.work.test.bean.UserBean;
//資料交流層介面定義
public interface IUserDao {
//插入使用者資料
void insertUserBean(UserBean user);
//修改使用者資料
void updateUserBean(UserBean user);
}
介面實現類定義:
IUserDao介面實現類UserDaoImpl類
package com.work.test.reverse; import com.work.test.bean.UserBean; //資料交流層介面實現,方法不實現功能,只是演示方法的可用性 public class UserDaoImpl implements IUserDao{ //新增使用者資料方法 public void insertUserBean(UserBean user) { System.out.println(user); } //更改使用者資料方法 public void updateUserBean(UserBean user) { System.out.println(user); } }
服務層(主要呼叫底層的介面)
介面程式碼:
IUserService介面定義
package com.work.test.reverse;
import com.work.test.bean.UserBean;
//服務層介面定義
public interface IUserService {
//儲存使用者資料
void saveUserBean(UserBean user);
//更改使用者資料
void updateUserBean(UserBean user);
}
介面實現類定義:
IUserService介面實現類UserServiceImpl(注意:在這個服務層實現類裡面我們用一個底層的介面引用實現對底層的呼叫,但是為什麼沒用直接在介面引用後new一個例項物件出來呢,這是因為要滿足依賴倒置原則,多層次之間相互依賴關係需要導致為抽象類或介面,而不是直接依賴於具體的實現,假如我們對UserDaoImpl類的類名進行了修改,那麼我們還要在這個類中修改相應的程式碼)
package com.work.test.reverse;
import com.work.test.bean.UserBean;
//服務層介面實現,方法不實現功能,只是演示方法的可用性
public class UserServiceImpl implements IUserService{
private IUserDao dao;//定義底層介面,因為服務層方法要呼叫底層介面實現的方法
//儲存使用者資料實現
public void saveUserBean(UserBean user) {
dao.insertUserBean(user);
}
//修改使用者資料實現
public void updateUserBean(UserBean user) {
dao.updateUserBean(user);
}
}
頂層程式碼:也就是介面層(用於呼叫業務層介面)這裡是測試
下面程式碼演示了:如何利用xml配置檔案對服務層實現類UserServiceImpl,給其內部底層IUserService介面引用進行物件例項化;和頂層中關於服務層IUserService介面引用物件的例項化
package com.work.test.reverse;
import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.gezhi.ooad.design.principle.bean.UserBean;
public class MainEnter {
private static IUserService userServiceImpl;//頂層呼叫服務層介面
/**
*該方法是利用xml文件裡的內容讀取出來,再利用反射實現例項物件的生成
*/
public static IUserService buildUserServiceImpl() {
String filePath = System.getProperty("user.dir") + File.separator + "beans.xml";
SAXReader sax = null;//定義使用sax讀取xml文件內容
Document document = null;
try {
sax = new SAXReader();
document = sax.read(new File(filePath));//得到文件物件
Element root = document.getRootElement();//得到文件的根節點
Iterator<Element> it = root.elementIterator();//得到迭代器,可獲取根節點下的子節點
Map<String,String> classInfo = new HashMap<>();//儲存一級子節點中類名及其地址的對映關係
Map<String,String> propertyInfo = new HashMap<>();//儲存服務介面中與需要例項物件的關係,也就是xml中二級子節點之間對映關係
while(it.hasNext()) {
Element ele = it.next();
String id = ele.attributeValue("id");
String className = ele.attributeValue("class");
classInfo.put(id, className);//將xml中讀出來的id與class地址進行鍵值對對映關係儲存
//判斷一級子節點下有沒有子節點
Iterator<Element> it2 = ele.elementIterator();
while(it2.hasNext()) {
Element ele2 = it2.next();
String ref = ele2.attributeValue("ref");//讀取出二級子節點中ref屬性包含的內容,也就是UserServiceImpl類中需要為IUserDao類介面引用建立例項物件的類
propertyInfo.put(id, ref);//建立一級id與ref內容之間的對映關係
}
}
//先各自建立物件
Map<String,Object> objInfo = new HashMap<>();//儲存id與類物件之間的關係的對映
Set keys = classInfo.keySet();//返回一級子節點中類名及其地址的對映關係中的節點
for (Object obj : keys) {
String key = (String) obj;
String className = classInfo.get(key);//通過節點名獲取對應的class物件的地址
Class<?> cls = Class.forName(className);//得到類物件,並載入該類
Object object = cls.newInstance();//例項化物件
objInfo.put(key, object);//裝入新的對映中
}
//然後再使用物件去建立關係
keys = propertyInfo.keySet();
Object master = null;
for (Object obj : keys) {
String key = (String) obj;
String value = propertyInfo.get(key);//獲得userDaoImpl這個屬性名,也就是ref的內容
//userServiceImpl ---- userDaoImpl之間的使用關係(userServiceImpl類中使用了userDaoImpl)
master = objInfo.get(key);//通過id值獲得上面例項化的物件
Object slave = objInfo.get(value);//通過ref的內容,也就是userDaoImpl這個字串名稱可以在objInfo這個對映中獲取到userDaoImpl這個類的例項物件
Field f = master.getClass().getDeclaredField("dao");//通過這個方法可以去操控屬性,私有的也可以,操控userServiceImpl下dao這個屬性
f.setAccessible(true);
f.set(master, slave);//進行賦值操作,也就是將dao需要的例項物件進行繫結
}
return (IUserService) master;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
userServiceImpl = buildUserServiceImpl();
UserBean user = new UserBean();
user.setId(1L);
user.setUserName("小馬");
userServiceImpl.saveUserBean(user);
}
}
xml程式碼:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userServiceImpl" class="com.work.test.reverse.UserServiceImpl">
<property name="dao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.work.test.reverse.UserDaoImpl"></bean>
</beans>