lec-14-DAO-v001
.pdfИСТОЧНИК ДАННЫХ
Чаще всего источником данных является база данных, например, RDBMS, OODBMS. Однако источниками данных могут быть, и XMLрепозиторий, и система плоских файлов. Источником данных может быть также другая система (традиционная/мэйнфрейм), служба (B2Bслужба или система обслуживания кредитных карт), или какой-либо репозиторий (LDAP).
Value Object или TransferObject используется для передачи данных.
DataAccessObject может использовать TransferObject для возврата данных клиенту. DataAccessObject может также принимать данные от клиента в объекте Transfer Object для их обновления в источнике данных. Частным случаем являются Entity компоненты или сущностный компоненты отсоединенные от контекста постоянства. Когда используемое хранилище данных может измениться при переходе от одной реализации к другой, используется стратегия Factory for Data Access Object, которая может быть реализована с применением паттерна Abstract Factory.
ДИАГРАММА КЛАССОВ ЭТОЙ СТРАТЕГИИ
ОПИСАНИЕ ДИАГРАММЫ
Эта диаграмма классов показывает базовый
генератор DAO, являющийся абстрактным классом, который наследуется и реализуется различными конкретными генераторами DAO для поддержки доступа к специфической реализации хранилища данных. Клиент может получить реализацию конкретного генератора DAO, например RdbDAOFactory, и использовать его для получения конкретных объектов DAO, работающих с этой конкретной реализацией хранилища данных. Например, клиент может получить RdbDAOFactory и использовать его для получения конкретных
DAO, таких как RdbCustomerDAO, RdbAccountDAO и др.
В нашей реализации мы будем стремиться к простоте, и будем использовать по одной фабрике на порождение объектов каждого типа, будь то источники данных, или разные реализации DAO. Это удается сделать с использованием механизма рефлексии. Это усложняет саму фабрику и несколько замедляет старт приложения, но упрощает положение тем, что на каждый тип порождаемых ресурсов используется только одна универсальная фабрика.
ОПИСАНИЕ РЕАЛИЗАЦИИ
Основные бизнес действия будут выполнять
классы служб AuthorService и BookService, находящиеся в пакете org.bookstore.services.
Для работы с базой данных реализуем шаблон DAO в виде специализированных классов и интерфейсов из пакета org.bookstore.dao, то есть с использованием POJO:
•BookStoreDAO – Интерфейс взаимодействия для служб
•BookStoreDAOFactory – Фабрика, порождающая объекты классов DAO
•DerbyDAO – Собственно реализация DAO для работы с базой данных Derby
•OracleDAO – Собственно реализация DAO для работы с базой данных Oracle
ПАРАМЕТРЫ ОПИСЫВАЮЩИЕ НАСТРОЙКУ DAO
<context-param>
<param-name>daos</param-name>
<param-value>oraDao;derbyDao</param-value> </context-param>
<context-param> <param-name>oraDao</param-name>
<param-value>daoClass=org.bookstore.dao.OracleDAO;dsname=oraCP
</param-value>
</context-param> <context-param>
<param-name>derbyDao</param-name>
<param-value>daoClass=org.bookstore.dao.DerbyDAO;dsname=derbyCP
</param-value>
</context-param>
Таким образом, у нас в приложении два класса, реализующие шаблон DAO, которые, естественно, должны использовать разные источники данных. Этими разными источниками могут быть разные схемы и разные базы данных.
ДОБАВЛЕНИЯ В КЛАСС APPCNTXLISTENER
Однако, дабы не сделать приложение работающим с распределенными транзакциями, а значит – слишком
сложным, мы этот дуализм дальше распространять не будем. Важно – обозначить идею.
Класс «слушателя» AppCntxListener должен быть расширен на предмет чтения информации описывающей DAO объекты и помещения ее в атрибуты приложения
public final class AppCntxListener implements ServletContextListener {
. . .
public void contextInitialized( ServletContextEvent event ) {
. . .
ServletContext servCtx = event.getServletContext();
. . .
// - - - - - - - DAOs - - - - - - - - - -
readDao( servCtx );
. . .
}
. . .
КЛАСС APPCNTXLISTENER
public void readDao( ServletContext p_servCtx ) { String s = p_servCtx.getInitParameter("daos"); if( s == null ) {
p_servCtx.log( LINESEP +
"<-!- DAO's List is empty -!->" + LINESEP );
}else {
String[] daoNames = s.split( Glo.DELIMITER ); Properties p = null;
for( |
String key : daoNames |
) { |
|
s |
= p_servCtx.getInitParameter( key ); |
|
|
p_servCtx.setAttribute( |
key, s ); |
} |
}
}
. . .
В пакте org.bookstore.model у нас располагаются классы, которые будут инкапсулировать данные объектов приложения.
Их пока немного: Author, Book, BookAuthor, Customer, Section.
Рассмотрим только один из них.
КЛАСС МОДЕЛИ AUTHOR
public class Author implements java.io.Serializable {
private int |
id; |
// id автора |
|
private String |
lastName; |
|
|
private String |
firstName; |
|
|
private String |
country; |
|
|
public Author( int |
p_id, |
String p_lastName, |
|
|
String p_firstName, String p_country ) { |
||
id = p_id; |
|
|
|
lastName |
= p_lastName; |
|
|
firstName = p_firstName; |
|
country = p_country;
}
public Author() {}
public int getId() { return id; }
public String getLastName() { return lastName; } public String getFirstName() { return firstName; } public String getCountry() { return country; }
public String toString() {
return "{ id=" + id + "; last name=" + lastName + "; first name=" + firstName + " country=" + country + "}";
}
}
НЕКОТОРЫЕ ОСОБЕННОСТИ РЕАЛИЗАЦИИ
В классы сущности можно частично поместить бизнес логику. Однако это не слишком хорошая идея. Поэтому у нас они будут иметь только атрибуты и правильные «геттеры» и «сеттеры», так как основная наша задача – задействовать DAO
Классы сущности характерны тем, что все свойства имеют выписанные на основе известных правил JavaBeans «геттеры», что очень важно при использовании класса в сочетании, например с Expression Language в рамках JSP страниц (смотри следующую тему). Кроме того неплохо было снабдить их и «сеттерами».
Идеология примера данной темы позаимствована из примеров, разработанных фирмой Sun.
Для того, чтобы можно было работать с разными типами DAO классов службы будут общаться с ними через интерфейс
BookStoreDAO.
ИНТЕРФЕЙС BOOKSTOREDAO
package org.bookstore.dao;
import java.util.List;
import org.bookstore.model.Author; import org.bookstore.model.Book; import org.bookstore.model.BookAuthor; import org.bookstore.model.Section; import org.bookstore.model.Customer;
/**
*This class is an interface which will be implemented
*by database specific code.
*This layer maps the relational data stored in the database to
*the objects needed by BookStore.
*/
public interface BookStoreDAO {
public void setDsName( String p_dsName ); public Author getAuthor( int auID )
throws DAOSysException;
public void getAuthors( List<Author> p_items ) throws DAOSysException;
. . .