Olá!
Sei que este post já é antigo, mas esta é uma questão que sempre me inquietou.
Então, para tratar diversas situações, principalmente relacionados às persistências de forma que as regras fiquem isoladas do controlador e da classe de domínio, eu resolvi criar uma nova camada, que chamei de camada de negócios.
A estratégia consiste em:
1) Quando eu identificar que alguma classe de domínio possui regras diferenciadas de negócio, eu crio uma classe de negócio que fica responsável por aplicar as regras e chamar a persistência dos objetos. Algo como VendasNegócio.
Por exemplo, se eu possui a classe de domínio faturamento.Vendas e se antes de vender eu precisasse checar algo sobre o cliente comprador, eu crio a classe VendasNegocio que fica em src/groovy/negocio/faturamento/VendasNegocio.groovy.
seu conteúdo seria algo como:
package negocio.faturamento;
class VendasNegocio {
public faturamento.Vendas insert(faturamento.Vendas _oObjDomain) {
/*
* coloco todas as regras aqui : checar o cliente comprador
*/
oObjSalvo = _oObjDomain.save(flush: true);
return oObjSalvo;
}
/*
* podem ser colocados todas as outras actions que existem no template
* controller.groovy do scaffold
*/
}
2) Alterar os templates do scaffold controller.groovy para:
a) verificar se existe uma classe de negócio para a classe de domínio em questão;
b) instanciar a classe de negócio, caso exista;
c) transferir a persistência para o método adequado do objeto da classe de negócio instanciada (insert, update, delete, list, etc);
as alterações seriam algo como:
def save = {
def ${propertyName} = new ${className}(params);
/*
* Caso exista uma classe de negócio implementada para esta classe
* utiliza a classe de negócio para salvar o objeto
*/
def oObjSalvo;
<%=
String sPackageName = "negocio.${packageName}";
String sClassName = "${className}Negocio";
def cNegocio = null;
try {
cNegocio = Class.forName(sPackageName + "." + sClassName, true, Thread.currentThread().getContextClassLoader());
def oMetodo = cNegocio.methods.findAll { it.name == "insert" };
if (oMetodo) {
String sRetorno = 'def o'+ sClassName + ' = new ' + sPackageName + '.' + sClassName + '(); oObjSalvo = o' + sClassName + '.insert(' + propertyName + ');';
sRetorno;
} else {
String sRetorno = 'oObjSalvo = ' + propertyName + '.save(flush: true);';
sRetorno;
}
} catch (ClassNotFoundException e) {
String sRetorno = 'oObjSalvo = ' + propertyName + '.save(flush: true);';
sRetorno;
}
%>
if(oObjSalvo) {
flash.message = message(code: 'default.created.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
redirect(action: "list")
} else {
return render(view: "create", model: [${propertyName}: ${propertyName}]);
}
}conclusão:Com esta estratégia eu isolo as regras de negócio, aproveito os templates e não preciso ficar construindo controladores para cada caso específico.