Общий дизайн реализации шаблона DAO
Я работаю над проектом GWT+Hibernate. Он состоит из различных модулей, из которых я назову два - Company и Login. Для каждого модуля я создал службу RPC, чтобы проект не заканчивался одной богоподобной службой, которая делает все.
для взаимодействия с базой данных я использую Hibernate APIs-чтобы быть конкретным, EntityManager и аннотации в POJOs.
кроме того, я создал общий класс DAO, который будет обрабатывать основные операции CRUD. Класс GenericDAO также будет обрабатывать EntityManager. Каждый класс обслуживания модуля расширит этот GenericDAO, чтобы он мог добавлять свои собственные методы запроса.
ниже приведен заглушка класса GenericDAO -
public class GenericDataAccessService<EntityType, PrimaryKeyType extends Serializable> {
// Constructor
@Override
public void save(EntityType newEntity) {
// TODO Auto-generated method stub
}
@Override
public void update(EntityType entity) {
// TODO Auto-generated method stub
}
@Override
public EntityType find(PrimaryKeyType primaryKey) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<EntityType> findByProperty(String property) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<EntityType> findAll() {
// TODO Auto-generated method stub
return null;
}
@Override
public void delete(PrimaryKeyType primaryKey) {
// TODO Auto-generated method stub
}
@Override
public void delete(EntityType entity) {
// TODO Auto-generated method stub
}
}
Теперь, скажем, я хочу еще один метод поиска для модуля компании. Итак, я пишу свой класс CompanyService таким образом -
public class CompanyService extends GenericDataAccessService<Company, int> {
public void addCompany(Company company) {
super.save(company);
}
public Company updateCompany(Company company) {
return super.update(company);
}
public List<Company> findMatchingCompanies(String companyName) {
return super.findByProperty(companyName);
}
public void deleteCompany (int companyId) {
super.delete(companyId);
}
public List<Company> findThroughSomeCustomSearch() {
// custom query code.
}
}
другие модули следуют за подобными шагами. Таким образом, я также могу добавить методы, не связанные с доступом к данным, к службам каждого модуля, тоже.
Теперь мне нужно выставить эти модули на стороне клиента. Я решил не выставлять класс GenericDAO каким-либо образом; поэтому для него нет интерфейса. Вместо этого, я создаю интерфейс для каждого модуля.
Итак, для CompanyService, это -
public interface CompanyService {
public void addCompany(Company company);
public Company updateCompany(Company company);
public List<Company> findMatchingCompanies(String companyName);
public void deleteCompany (int companyId);
public List<Company> findThroughSomeCustomSearch();
}
интерфейсы других модулей идут таким же образом.
это хороший дизайн? GenericDAO сохраняет некоторый шаблонный код управления сеансами и основные операции CRUD. Однако это уже сократилось до 3-4 строк код для каждого метода, из-за Hibernate API. В этом случае я не нахожу другого использования GenericDAO. Или я делаю это неправильно?
пожалуйста предложите лучшие пути чем это, в случае если эта конструкция не хороша достаточно.
изменить: Я хотел бы знать, какие имена вы бы дали сервисным модулям в этом случае. Я сейчас использую суффикс "Impl", но он застрял у меня в горле. Например, для модуля компании , Интерфейс - CompanyService Класс - CompanyServiceImpl
предложение получше?
1 ответов
Я думаю, есть несколько вещей, которые вы могли сделать, чтобы улучшить это:
соединение:
в большинстве случаев композиция предпочтительнее наследования. Ваши услуги тесно связаны из-за такого отношения. Я его меняю, вместо этого использую композицию следующим образом:
public class CompanyService {
private GenericDataAccessService<Company, int> dao; // interface
public void addCompany(Company company) {
dao.save(company);
}
....
}
чтобы сломать зависимость, поле dao должно быть абстрактным классом или интерфейсом (я не знаю ни вашего кода, ни ваших потребностей, ни java), чтобы позволит вам ввести его.
Testeability:
инъекция зависимостей этих классов также поможет вам проверить ваш код, легко вводя их фиктивные экземпляры.
ненужные операции:
использование наследования заставляет вас иметь операции, которые, вероятно, вы не хотите разрешать. Например, просто представьте, что у вас есть AuditingDataService следующим образом:
public class AuditingService extends GenericDataAccessService<Audit, int>
Если вы это сделаете, yout AuditingService будет унаследовать удалить способ!!! Ты чувствуешь этот запах так же сильно, как и я? Это приведет вас к следующей точке.
анти-шаблон
в предыдущем примере (метод delete для аудита записей журнала) вы будете вынуждены переопределить его с помощью вообще ничего или бросать исключение метод, чтобы предотвратить его использование... МММ.... МММ... Это может быть хорошим дизайном?
вывод:
Я думаю, что это не так, просто потому, что наследование не подходит здесь.
забудьте на мгновение о LoCs и сосредоточились на изменении дизайна.
обновление:
Java имеет свои собственные соглашения об именах, и если well Impl-ужасный суффикс, это одно из тех соглашений, которые понимает и разделяет каждый программист java. Так что, думаю, все в порядке.