通用DAO模式实现设计

Jay*_*oot 7 gwt design-patterns hibernate genericdao

我正在开发一个GWT + Hibernate项目.它由各种模块组成,其中我将命名为两个 - 公司和登录.对于每个模块,我已经创建了一个RPC服务,这样项目就不会有一个像神一样的服务来完成所有事情.

为了与数据库进行交互,我使用了Hibernate API - 具体来说,是POJO中的EntityManager和Annotations.

另外,我创建了一个Generic 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

    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我想再为公司模块寻找一种方法.所以,我写了我的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.
    }
}
Run Code Online (Sandbox Code Playgroud)

其他模块也遵循类似的脚步.这样,我也可以为每个模块的服务添加非数据访问相关的方法.

现在,我需要在客户端公开这些模块.我选择不以任何方式公开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();
}
Run Code Online (Sandbox Code Playgroud)

其他模块的接口也是一样的.

这是一个很好的设计吗?GenericDAO确实保存了一些会话管理和基本CRUD操作的样板代码.但是,由于Hibernate API,每个方法已经减少了3-4行代码.在这种情况下,我没有发现GenericDAO的任何其他用途.或者我以错误的方式实施它?

如果这种设计不够好,请建议比这更好的方法.

编辑:我想知道在这种情况下你会给服务模块的名字.我现在正在使用"Impl"后缀,但感觉它被困在我的喉咙里.例如,对于Company模块,Interface - CompanyService Class - CompanyServiceImpl

一个更好的建议?

lon*_*ero 9

我认为你可以采取一些措施来改善这一点:

耦合:

大多数时候,组合物优于遗传.由于这种关系,您的服务是强烈耦合的.我的目的是改变它,使用组合代替如下:

public class CompanyService  {
    private GenericDataAccessService<Company, int> dao; // interface 

    public void addCompany(Company company) {
        dao.save(company);
    }
    ....
}
Run Code Online (Sandbox Code Playgroud)

为了打破依赖,dao字段应该是一个抽象类或接口(我既不知道你的代码也不知道你的需要也不知道java)以允许你注入它.

可测性:

注入这些类的依赖项也可以帮助您测试代码,轻松地为它们注入模拟实例.

不需要的操作:

使用继承强制您进行可能不希望允许的操作.例如,假设您有一个AuditingDataService,如下所示:

public class AuditingService extends GenericDataAccessService<Audit, int> 
Run Code Online (Sandbox Code Playgroud)

如果你这样做,你的AuditingService将继承一个Delete方法!你能感受到和我一样强烈的气味吗?它将驱动您到以下几点.

反模式

在上一个示例中(审计日志条目的删除方法),您将被强制使用do-nothing或throw -exception方法覆盖它以防止有人使用它...嗯...这可能是一个好的设计?

结论:

我认为事实并非如此,仅仅因为继承不适合这里.

忘了关于LoC的一刻,专注于改变设计.

更新:

Java有自己的命名约定,如果Impl是一个非常糟糕的后缀,它是每个java程序员理解和共享的约定之一.所以,我认为这没关系.