Orientação a objetos - técnicas

15 respostas
Metallica

Olá,

Eu já li bastante sobre OO mas ainda tenho algumas dúvidas cruciais, como estou iniciando esse projeto, gostaria de saber as técnicas / convenções para facilitar os problemas que poderão surgir.

É o velho exemplo de aplicação bancária:

Tenho um cliente:
public class Cliente {
    
    private String  nome;
    private String  rg;
    private String  fraseSecreta;
    private String  dataNascimento;
    
    private Conta conta; //O cliente tem uma Conta (HAS-A)
    
    //getters e setters
    //equals e toString sobrescritos
}

1) A primeira dúvida minha: essa classe Cliente seria um bean, correto? E o que o bean deve conter é apenas isso(variáveis e getters/setters)? Métodos como saque(), deposito(), transferenciaBancaria() devem ir em outra classe? É a questão da coesão.

2) Sobre datas ,no caso a data de nascimento, usar um objeto String para armazená-la é a melhor escolha?

Ainda no mesmo pacote tenho outra classe: Conta.
public class Conta {
    private String  numeroConta;
    private int       numeroAgencia;
    private double  saldo;
    
    private enum Tipo{ SIMPLES, ESPECIAL, POUPANCA};

    //getters e setters
}

3)A conta pode ter três tipos: Simples, Especial ou Poupança.
Usar enum é o melhor jeito nesse caso?

4)No caso desse exemplo, haverá um Gerente, que será responsável pelo cadastro de Clientes, porém ele também pode fazer
tudo que um Cliente faz. Nesse caso eu devo fazer então Gerente extends Cliente, mas em Cliente não vai ter os métodos de operação citados acima(saldo, deposito) ou vai? As variáveis de instância não devem ser herdadas não é?

5)Para cadastro, será feito em um banco de dados, eu devo criar uma classe separada para essa interação com o banco, certo? Ou o gerente vai ter um método? (Algo como: public void cadastraCliente(Cliente c) )

Na verdade isso seria a parte dos modelos (o "M" do MVC) pois é pra ser usado numa aplicação com JSP.

Bom, é isso, como estou no meio acadêmico, as vezes a gente aprende de um jeito que não é o mais prático ou falta algumas dicas dos PROs hehe.

Abraços!
Grato

15 Respostas

paulofernandesjr
Metallica:
Olá,

Eu já li bastante sobre OO mas ainda tenho algumas dúvidas cruciais, como estou iniciando esse projeto, gostaria de saber as técnicas / convenções para facilitar os problemas que poderão surgir.

É o velho exemplo de aplicação bancária:

Tenho um cliente:
public class Cliente {
    
    private String  nome;
    private String  rg;
    private String  fraseSecreta;
    private String  dataNascimento;
    
    private Conta conta; //O cliente tem uma Conta (HAS-A)
    
    //getters e setters
    //equals e toString sobrescritos
}

1) A primeira dúvida minha: essa classe Cliente seria um bean, correto? E o que o bean deve conter é apenas isso(variáveis e getters/setters)? Métodos como saque(), deposito(), transferenciaBancaria() devem ir em outra classe? É a questão da coesão.

eu tenho uma seguinte idéia sobre tudo isso

getters e setters só devem ser criados se forem necessários, caso contrario não crie!!!

as operações [regras de negócio] que são do objeto, creio que devam ficar no objeto

as regras de negócio do sistema no Controller do MVC

Metallica:

2) Sobre datas ,no caso a data de nascimento, usar um objeto String para armazená-la é a melhor escolha?

as classes que tratam tipos, foram feitas para tratar tipos!

data de nascimento ao meu ver não é String e sim Date

Metallica:
Ainda no mesmo pacote tenho outra classe: Conta.
public class Conta {
    private String  numeroConta;
    private int       numeroAgencia;
    private double  saldo;
    
    private enum Tipo{ SIMPLES, ESPECIAL, POUPANCA};

    //getters e setters
}

3)A conta pode ter três tipos: Simples, Especial ou Poupança.
Usar enum é o melhor jeito nesse caso?

desconheço sobre enum
hehe

desculpa

Metallica:
4)No caso desse exemplo, haverá um Gerente, que será responsável pelo cadastro de Clientes, porém ele também pode fazer tudo que um Cliente faz. Nesse caso eu devo fazer então Gerente extends Cliente, mas em Cliente não vai ter os métodos de operação citados acima(saldo, deposito) ou vai? As variáveis de instância não devem ser herdadas não é?

ao meu ver são duas coisas diferentes!
você pode ter Pessoa e falar que a pessoa pode ser cliente ou funcionario do banco e as operações que o gerente faz você deve tratar com permissão de acesso.

se eu estiver errado me corrijam, por favor

Metallica:
5)Para cadastro, será feito em um banco de dados, eu devo criar uma classe separada para essa interação com o banco, certo? Ou o gerente vai ter um método? (Algo como: public void cadastraCliente(Cliente c) )

Na verdade isso seria a parte dos modelos (o "M" do MVC) pois é pra ser usado numa aplicação com JSP.

Bom, é isso, como estou no meio acadêmico, as vezes a gente aprende de um jeito que não é o mais prático ou falta algumas dicas dos PROs hehe.

Abraços!
Grato



as classes são o Model, o Controller que deve fazer toda a persistência [ gravar em qualquer lugar, banco por exemplo ] e o View são suas páginas JSP

espero ter ajudado, qualquer problema, poste novamente, se eu errei algo por favor me corrijam

abraço

tnaires

paulofernandesjr,

Regras de negócio ficam no modelo, e não no controle. O controle apenas traduz os eventos ocorridos na view em requisições de alteração do estado do sistema ( o modelo ). Tudo o que representa o estado do sistema é modelo, incluindo persistência.

paulofernandesjr

tnaires:
paulofernandesjr,

Regras de negócio ficam no modelo, e não no controle. O controle apenas traduz os eventos ocorridos na view em requisições de alteração do estado do sistema ( o modelo ). Tudo o que representa o estado do sistema é modelo, incluindo persistência.

então a persistência deve ficar no modelo?

quando me referi a regras de negócio, quiz dizer regras de negócio do objeto devem ficar no objeto

as regras do sistema ficam no Controller ou no Model? agora você me confundiu!

L

Ser coeso é ter uma classe (ou método, ou pacote, ou módulo, ou qualquer divisão que se faça na sua aplicação) que possua apenas uma única responsabilidade, e que deve ser completa. Não pode haver uma divisão entre dados e funcionalidades, as duas coisas são relacionadas. Crie uma classe Cliente com os métodos de negócios, além dos getters/setters (mas somente o que for necessário).

Não. Use classes específicas do tipo java.util.Date. Se tiver algo como dataInicial e dataFinal, recomendo ainda criar uma classe chamada Interval onde armazena os dois intervalos de data. (link)

Metallica:
3)A conta pode ter três tipos: Simples, Especial ou Poupança.
Usar enum é o melhor jeito nesse caso?

Não. O melhor jeito é usar o [google]strategy pattern[/google]

Metallica:
4)No caso desse exemplo, haverá um Gerente, que será responsável pelo cadastro de Clientes, porém ele também pode fazer
tudo que um Cliente faz. Nesse caso eu devo fazer então Gerente extends Cliente, mas em Cliente não vai ter os métodos de operação citados acima(saldo, deposito) ou vai? As variáveis de instância não devem ser herdadas não é?

Não faça nada disso. Gerente é distinto de Cliente, mesmo que todos os gerentes tenham conta no próprio banco em que trabalha. Isso porque quando o Gerente Fulano faz um saque na sua própria conta, ele é um cliente; quando ele olha a movimentação financeira de um correntista para oferecer-lhe um empréstimo, ele é um gerente.

Complicado, se a regra do banco diz que nenhum cliente pode abrir uma conta sem autorização de um gerente, pode ser interessante colocar na classe gerente um método como void abrirConta(Cliente c). Na prática, não existe uma resposta pronta pra isso.

sergiotaborda

É uma questão de separação de responsabilidade. Não é o cliente que saca dinheiro é o banco que retira uma quantidade e dinheiro da conta do cliente conforme o cliente pedir. Sim, a transferencia deve estar em outra classe. conta é apenas um nome para um historico de lancamentos (debitos e creditos).

Obviamente não. A escolha certa é Date. Dados devem ser puros. Ou seja, não dependerem de formatação.
Traduzir um data numa string implica em usar formatos e portanto viola essa regra simples e básica.

Sim e não. Para o campo tipo, sim, enum é o melhor.
Contudo porque as contas tem diferentes tipos ? … não será porque existem regras que se conportam diferente conforme o tipo ? Nesse caso vc faria algo como … ?

if ( conta.getTipo() == Tipo.SIMPLES) {

} else if (conta.getTipo() == Tipo.ESPECIAL){

}
...

Não. Não faria. Vc usaria o padrão Strategy. Em tempo é possivel converter enum numa implementação de strategy portanto, em geral, sim. é bom usar enum.

NÂO! Gerente NÂO É um cliente. Logo não ha relação de herança entre eles, logo não pode usar extends.
É a operação da transação da conta que pode ser invocada pelo cliente ou pelo gerente.

transferencia ( responsavel , valor, contaA, contaB )

Numa orientação 100% OO poderiamos pensar que o método cadastrasCliente em Gerente faz sentido já que traduz a realidade melhor que qualquer outra. Na prática vc pode até usar isso, mas necessitará sempre de um outro objeto para a interação com o banco em si: o famoso e famigerado DAO.

sim, essas classes seria utilizadas pelo M do MVC : o modelo, mas elas não seriam o M em si mesmas. Lembre-se que MVC não é uma forma de ligar camadas do seu sistema é apenas uma forma de estruturar a camada internamente.
Existem mais classes que podemos considerar do modelo, como o DAO, por exemplo.

L

Persistência sempre fica no modelo. O que muda é a abordagem. No pattern Active Record, as regras de acesso à base de dados está na própria classe de domínio. No pattern Data Mapper (Hibernate usa esse padrão), existe um módulo separado do domínio (o data mapper) que faz a persistência. Porém o fato do data mapper ficar fora das classes de domínio não faz dele parte do Controller.

Regras de sistema e de negócio ficam no Model. Talvez o que você entende como regra de sistema seja o que é chamado de [google]Service Layer[/google], que é útil para demarcar uma transação entre vários objetos. Mas essa camada é Model.

O controller do MVC seria melhor chamado de input controller, que executa mais ou menos os seguintes passos:

  • interpreta o que foi recebido pela view
  • chama o método de um objeto do model
  • delega a renderização para a view apropriada, dependendo do que foi recebido pela chamada do método do model

Mais do que isso, viola o MVC.

paulofernandesjr

ah beleza…

agora acho que comecei a entender…

apenas para finalizar…

o DAO fica no Controller que é invocado a partir do Model?

desenhando um pouco

VIEW[jsp] -> CONTROLLER -> MODEL -> CONTROLLER[DAO] -> ALTERA O MODEL -> DEVOLVE PARA O CONTROLLER -> QUE ENVIA PARA O VIEW

falei besteira?

Metallica

Obrigado pelas dicas pessoal.
Ainda tem algumas coisas obscuras pra mim :

O gerente então fica com o método pra cadastrar o cliente no banco? Ou eu coloco isso na classe dao?

Pelo cliente ter uma conta (HAS-A), o que faz muito sentido, eu também devo passar essa Conta por parâmetro no método de cadastrar certo? O problema é que ela é abstrata, já que tem Conta Especial, poupança ou especial apenas.

O DAO afinal, serve pra separar código de banco de dados dos beans certo? Eu vi um exemplo que o autor criava uma interface com tais métodos (salvar, excluir etc) e JDBC e Hibernate implementavam ela. No meu caso não tem nada disso, é DAO mesmo assim?
Se eu criasse uma interface dessas não faria lá muito sentido.

Bem, aqui vai alguns esboços para melhor entendimento :
public class Gerente {
    public void cadastraCliente(Cliente c, Conta conta){
         //Código de banco de dados (PreparedStatement, Connection, ResultSet e cia ) vem aqui?
    }
}
Ou faço isso?
public class Dao {
    public void cadastraCliente(Cliente c, Conta conta){

    }
}

Muito obrigado!

sergiotaborda

Metallica:
Obrigado pelas dicas pessoal.
Ainda tem algumas coisas obscuras pra mim :

O gerente então fica com o método pra cadastrar o cliente no banco? Ou eu coloco isso na classe dao?

Vc escolhe.

O cliente tem uma conta associada, mas isso significa apenas que ele tem um getConta() e não que tem um attributo conta. A conta é criada quando o cliente for criado. Quando o cliente é criado é dito que tipo de conta é.

Sim, mais ou menos isso… não necessáriamente dos beans. O DAO serve para encaspular o uso da api de JDBC

tudo bem. O DAO não tem que seguir uma interface especifica. Segue-se essa (CRUD) por padrao já que é a mais utilizada. Vc vai ver que se tentar implementar implementar o DAO vai acabar entendendo que esses são os métodos de que precisa.

Ok. pode ser. Nesse caso vc não está usando o DAO, mas tudo bem; ele não é obrigatorio.

Metallica
sergiotaborda:
Bem, aqui vai alguns esboços para melhor entendimento :
public class Gerente {
    public void cadastraCliente(Cliente c, Conta conta){
         //Código de banco de dados (PreparedStatement, Connection, ResultSet e cia ) vem aqui?
    }
}

Ok. pode ser. Nesse caso vc não está usando o DAO, mas tudo bem; ele não é obrigatorio.


Bom, eu acabei preferindo colocar o método cadastraCliente na minha classe DAO, porque lá é que tem objetos PreparedStatement, ResultSet etc. Achei que se eu colocasse esse método no Gerente, teria que ter esses objetos da API JDBC no Gerente, e iria "sujar" meu código na classe Gerente.

/** Classe DAO
*/
public void cadastraCliente(Cliente c, Conta conta){
        try{
            /*Cadastrando a conta*/
            this.ps = this.con.prepareStatement(this.iCadastraConta);
            this.ps.setString(1, conta.getNumeroConta());
            //Esse jeito de implementar está certo mesmo né?
Tá certo assim?
/** Classe Gerente
*/
//Essa classe só importa a classe Dao e usa os métodos dela.

public void cadastrarCliente(Cliente c, Conta conta) {
            Dao d = new Dao();
            d.abreConexao();
            d.cadastraCliente(c,conta);
            d.fechaConexao();
    }

PS: Existe algum livro/tutorial na internet ensinando boas práticas de codificação mostrando exemplos(Não só de JDBC)? Sei que tem o livro "Effective Java" do excelentíssimo Joshua Bloch, mas acho que JDBC ele não fala .

L

paulofernandesjr:
o DAO fica no Controller que é invocado a partir do Model?

desenhando um pouco

VIEW[jsp] -> CONTROLLER -> MODEL -> CONTROLLER[DAO] -> ALTERA O MODEL -> DEVOLVE PARA O CONTROLLER -> QUE ENVIA PARA O VIEW

Não, DAO está no Model.

Nenhum Model pode ter referências de Controller, nem de View.

Desenhando, ficaria assim:

VIEW[no envio de formulário] -> CONTROLLER -> OBJETO DE DOMÍNIO[model] -> DAO[ainda model] -> ALTERA ESTADO DO OBJETO DE DOMÍNIO -> RETORNA PARA O CONTROLLER -> DECISÃO DE QUAL VIEW ESCOLHER[no controller ainda] -> NOVO JSP[view] -> BUSCA DE ATRIBUTOS NO MODEL[via expression language]

Zeed01

Boa noite colegas !

No seu modelo o que acontece se um cliente tiver mais que uma conta ?

[]s

Metallica

Zeed01:
Boa noite colegas !

No seu modelo o que acontece se um cliente tiver mais que uma conta ?

[]s


Como você pode perceber, não acontece nada, porque não é possível :-o
Colocar um vetor de contas eu acho impraticável, talvez uma ArrayList seja uma boa, mas isso quando eu acabar a versão 1.0.

Zeed01

Boa noite Colegas !

Na verdade o que pensei foi que Cliente não deveria ter um atributo Conta.
Talvez conta devesse ter um Cliente.

[]s

Ironlynx

Aí se faz necessário a pergunta: Quem tem que saber sobre as contas?
O sistema(O banco).Ao cliente, não cabe saber como o sistema gerencia sua conta.E dependendo da situação, há atributos de Conta que o Cliente não deveria saber(tá, na verdade deveria, mas a gerência não faz questão de que você saiba).
Dependendo do banco, eles realmente associam Conta ao Cliente,e não o Cliente a várias Contas pois o objeto principal de controle do Banco é a Conta(mas o gerente tenta dizer sempre que é você…).

Acho essa a melhor abordagem, passando um “tipo de conta”(geralmente liberado pelo Gerente), e não um atributo conta.

Metallica, um bom artgo sobre MVC é o do Philip: http://fragmental.com.br/wiki/index.php?title=MVC_e_Camadas

Criado 22 de abril de 2008
Ultima resposta 24 de abr. de 2008
Respostas 15
Participantes 7