摘要:此的功能是從應用程序中隱藏在底層存儲機制中執行操作所涉及的所有復雜性。這正是模式試圖解決的問題。將模式與一起使用開發人員普遍認為的發布將模式的功能降級為零,因為該模式只是實體經理提供的另一層抽象和復雜性。在這種情況下,模式有其自己的位置。
案例概述
數據訪問對象(DAO)模式是一種結構模式,它允許我們使用抽象API將應用程序/業務層與持久層(通常是關系數據庫,但它可以是任何其他持久性機制)隔離開來。
此API的功能是從應用程序中隱藏在底層存儲機制中執行CRUD操作所涉及的所有復雜性。這允許兩個層分別進化而不知道彼此之間的任何事情。
在本文中,我們將深入研究模式的實現,并且我們將學習如何使用它來抽象調用JPA實體管理器。
簡單實施
要了解DAO模式的工作原理,讓我們創建一個基本示例。
假設我們想要開發一個管理用戶的應用程序。為了使應用程序的域模型完全不受數據庫的影響,我們將創建一個簡單的DAO類,它將保持這些組件彼此完美地分離。
由于我們的應用程序將與用戶一起工作,我們需要定義一個類來實現其模型:
public class User { ????? ????private String name; ????private String email; ????? ????// constructors / standard setters / getters }
User類只是用戶數據的普通容器,因此它不實現任何其他值得強調的行為。
當然,我們在這里需要做的最相關的設計選擇是如何使使用這個類的應用程序與任何可以在某個時候實現的持久性機制隔離開來。
這正是DAO模式試圖解決的問題。
DAO API
讓我們定義一個基本的DAO層,這樣我們就可以看到它如何使域模型與持久層完全分離。
這是DAO API:
public interface Dao{ ????? ????Optional get(long id); ????? ????List getAll(); ????? ????void save(T t); ????? ????void update(T t, String[] params); ????? ????void delete(T t); }
從鳥瞰的角度來看,很明顯Dao接口定義了一個抽象API,它對類型為T的對象執行CRUD操作。
由于接口提供的抽象級別很高,因此很容易創建與用戶對象一起工作的具體的、細粒度的實現。
UserDao類
讓我們定義Dao接口的特定于用戶的實現:
public class UserDao implements Dao{ ????? ????private List users = new ArrayList<>(); ????? ????public UserDao() { ????????users.add(new User("John", "john@domain.com")); ????????users.add(new User("Susan", "susan@domain.com")); ????} ????? ????@Override ????public Optional get(long id) { ????????return Optional.ofNullable(users.get((int) id)); ????} ????? ????@Override ????public List getAll() { ????????return users; ????} ????? ????@Override ????public void save(User user) { ????????users.add(user); ????} ????? ????@Override ????public void update(User user, String[] params) { ????????user.setName(Objects.requireNonNull( ??????????params[0], "Name cannot be null")); ????????user.setEmail(Objects.requireNonNull( ??????????params[1], "Email cannot be null")); ????????? ????????users.add(user); ????} ????? ????@Override ????public void delete(User user) { ????????users.remove(user); ????} }
所述的UserDAO類實現所有用于獲取,更新和刪除所需要的功能的用戶的對象。
為簡單起見,User List的作用類似于內存數據庫,在構造函數中填充了幾個User對象。
當然,重構其他方法很容易,因此它們可以用于關系數據庫。
雖然User和UserDao類在同一個應用程序中獨立共存,但我們仍然需要看看后者如何用于保持持久層對應用程序邏輯的隱藏:
public class UserApplication { ? ????private static Dao userDao; ? ????public static void main(String[] args) { ????????userDao = new UserDao(); ????????? ????????User user1 = getUser(0); ????????System.out.println(user1); ????????userDao.update(user1, new String[]{"Jake", "jake@domain.com"}); ????????? ????????User user2 = getUser(1); ????????userDao.delete(user2); ????????userDao.save(new User("Julie", "julie@domain.com")); ????????? ????????userDao.getAll().forEach(user -> System.out.println(user.getName())); ????} ? ????private static User getUser(long id) { ????????Optionaluser = userDao.get(id); ????????? ????????return user.orElseGet( ??????????() -> new User("non-existing user", "no-email")); ????} }
這個例子是人為的,但簡而言之,它顯示了DAO模式背后的動機。在這種情況下,main方法只使用UserDao實例對幾個User對象執行CRUD操作。
此過程最相關的方面是UserDao如何從應用程序中隱藏有關如何持久,更新和刪除對象的所有低級詳細信息。
將模式與JPA一起使用
開發人員普遍認為JPA的發布將DAO模式的功能降級為零,因為該模式只是JPA實體經理提供的另一層抽象和復雜性。
毫無疑問,在某些情況下這是事實。即便如此,有時我們只想向我們的應用程序公開實體管理器API的一些特定于域的方法。在這種情況下,DAO模式有其自己的位置。
JpaUserDao類
話雖如此,讓我們創建一個Dao接口的新實現,這樣我們就可以看到它如何封裝JPA實體管理器提供的開箱即用功能:
public class JpaUserDao implements Dao{ ????? ????private EntityManager entityManager; ????? ????// standard constructors ????? ????@Override ????public Optional get(long id) { ????????return Optional.ofNullable(entityManager.find(User.class, id)); ????} ????? ????@Override ????public List getAll() { ????????Query query = entityManager.createQuery("SELECT e FROM User e"); ????????return query.getResultList(); ????} ????? ????@Override ????public void save(User user) { ????????executeInsideTransaction(entityManager -> entityManager.persist(user)); ????} ????? ????@Override ????public void update(User user, String[] params) { ????????user.setName(Objects.requireNonNull(params[0], "Name cannot be null")); ????????user.setEmail(Objects.requireNonNull(params[1], "Email cannot be null")); ????????executeInsideTransaction(entityManager -> entityManager.merge(user)); ????} ????? ????@Override ????public void delete(User user) { ????????executeInsideTransaction(entityManager -> entityManager.remove(user)); ????} ????? ????private void executeInsideTransaction(Consumer action) { ????????EntityTransaction tx = entityManager.getTransaction(); ????????try { ????????????tx.begin(); ????????????action.accept(entityManager); ????????????tx.commit(); ????????} ????????catch (RuntimeException e) { ????????????tx.rollback(); ????????????throw e; ????????} ????} }
該JpaUserDao類是能夠與由JPA實現所支持的任何關系數據庫的工作。
此外,如果我們仔細研究這個類,我們將會意識到使用Composition和Dependency Injection如何允許我們只調用應用程序所需的實體管理器方法。
簡而言之,我們有一個特定于域的定制API,而不是整個實體管理器的API。
重構User類
在這種情況下,我們將使用Hibernate作為JPA默認實現,因此我們將相應地重構User類:
@Entity @Table(name = "users") public class User { ????? ????@Id ????@GeneratedValue(strategy = GenerationType.AUTO) ????private long id; ????? ????private String name; ????private String email; ????? ????// standard constructors / setters / getters }
以編程方式引導JPA實體管理器
假設我們已經在本地或遠程運行MySQL的工作實例,并且數據庫表“users”填充了一些用戶記錄,我們需要獲得一個JPA實體管理器,因此我們可以使用JpaUserDao類來執行CRUD操作數據庫。
在大多數情況下,我們通過典型的“persistence.xml”文件來實現這一點,這是標準方法。
在這種情況下,我們將采用“xml-less”方法,通過Hibernate方便的EntityManagerFactoryBuilderImpl類獲取具有普通Java的實體管理器。
有關如何使用Java引導JPA實現的詳細說明,請查看用Java編程引導JPA。
UserApplication類
最后,讓我們重構一下初始的UserApplication類,這樣它就可以使用JpaUserDao實例并在User實體上執行CRUD操作:
public class UserApplication { ? ????private static DaojpaUserDao; ? ????// standard constructors ????? ????public static void main(String[] args) { ????????User user1 = getUser(1); ????????System.out.println(user1); ????????updateUser(user1, new String[]{"Jake", "jake@domain.com"}); ????????saveUser(new User("Monica", "monica@domain.com")); ????????deleteUser(getUser(2)); ????????getAllUsers().forEach(user -> System.out.println(user.getName())); ????} ????? ????public static User getUser(long id) { ????????Optional user = jpaUserDao.get(id); ????????? ????????return user.orElseGet( ??????????() -> new User("non-existing user", "no-email")); ????} ????? ????public static List getAllUsers() { ????????return jpaUserDao.getAll(); ????} ????? ????public static void updateUser(User user, String[] params) { ????????jpaUserDao.update(user, params); ????} ????? ????public static void saveUser(User user) { ????????jpaUserDao.save(user); ????} ????? ????public static void deleteUser(User user) { ????????jpaUserDao.delete(user); ????} }
即使示例確實非常有限,它仍然有助于演示如何將DAO模式的功能與實體管理器提供的功能集成。
在大多數應用程序中,有一個DI框架,它負責將JpaUserDao實例注入UserApplication類。為簡單起見,我們省略了此過程的詳細信息。
最相關的點這里要強調的是如何在JpaUserDao類有助于保持UserApplication類完全無關關于持久層如何執行CRUD操作。
此外,由于Dao接口和實體管理器提供的抽象級別,我們可以將MySQL交換到任何其他RDBMS(甚至是平面數據庫),而且,我們的應用程序仍將按預期繼續工作。
案例結論
在本文中,我們深入研究了DAO模式的關鍵概念,如何在Java中實現它,以及如何在JPA的實體管理器之上使用它。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73167.html
摘要:適配器模式的結構通過繼承實現通過委讓實現代碼實現目標類使用數據線適配類使用轉適配線主函數與在適配器模式中的應用當前,不少公司使用整合進行系統開發。 Java 23種設計模式----適配器模式 1、面向對象OO = 面向對象分析OOA + 面向對象設計OOD + 面向對象編程OOP 2、編程是一門技術、同時也是一門藝術 3、應該面向接口編程,而不是面向實現編程 什么是設計模式 設計模式是...
摘要:何為簡單點來定義就是切面,是一種編程范式。定義一個切面的載體定義一個切點定義一個為,并指定對應的切點一個注冊配置類,啟動容器,初始化時期獲取對象,獲取對象時期,并進行打印好了,這樣我們整體的代理就已經完成。 問題:Spring AOP代理中的運行時期,是在初始化時期織入還是獲取對象時期織入? 織入就是代理的過程,指目標對象進行封裝轉換成代理,實現了代理,就可以運用各種代理的場景模式。 ...
閱讀 2031·2023-04-25 15:24
閱讀 1575·2019-08-30 12:55
閱讀 1615·2019-08-29 15:27
閱讀 470·2019-08-26 17:04
閱讀 2406·2019-08-26 10:59
閱讀 1797·2019-08-26 10:44
閱讀 2193·2019-08-22 16:15
閱讀 2587·2019-08-22 15:36