[MÚSICA] [MÚSICA] Olá, bem vindo ao curso de orientação a objetos com Java. Eu sou o Clovis Fernandes e hoje iremos falar do princípio "Tell, Don' Ask". Na aula anterior nós vimos que o acesso a dados internos da classe diretamente, ou via "Getters e setters" isso não era uma coisa boa, havia acoplamento muito forte. A ideia na aula de hoje é usando esse princípio, diminuir sensivelmente a quantidade de dependência entre uma classe relação a outra. No decorrer então da aula, eu vou mostrar a você, uma forma de usando o princípio "Tell, don't ask!" como tratar esses problemas de acoplamento alto devido ao "Getter e Setter" associado a dados internos. Na aula anterior a gente viu que isso não era uma coisa boa, era muito ruim. Nós deixamos bem claro, nós carimbamos aquilo como uma coisa ruim. E na aula de hoje, nós iremos então mostrar como transformar aquela coisa que era ruim, numa coisa que é boa, numa coisa que deixa a gente mais feliz. Feliz que sentido? O acoplamento que era alto, vai ser reduzido. É esse o objetivo da aula de hoje. Esse conceito que eu estou mostrando aí Inglês "Tell, don' ask!", ele corresponde a "Ordene, não peça!", ou seja, não peça pela informação que você vai usar para realizar uma determinada tarefa. Ao invés, o que é que você faz? Você faz com que o objeto do qual você estava querendo obter essa informação faça a tarefa para você. É isso que está no sentido para você ordenar, não pedir a informação para você e você querer fazer. É isso que é a diferença importante. Eu estou realçando aí os pontos que são importantes que é no sentido de que eu sempre tenho objetivo do que eu quero fazer. Para isso vou precisar de algumas informações. Eventualmente essas informações estão objetos de outras classes. Ao invés de querer obter essas informações para eu realizar a ação que eu quero fazer, o melhor lugar é no outro objeto porque a informação está lá. Então eu simplesmente passo para esse objeto a lógica da ação que eu estava querendo. Quando eu defini a lógica da responsabilidade anteriormente eu não estava pensando nesse princípio ao fazer a revisão da minha lógica dessa forma, eu percebo que quem deve fazer isso é o outro objeto, não eu. Então há uma distribuição. Isso faz parde da modelagem CRC. Vamos exemplificar então usando a classe "A" e "B" aí do meu exemplo que eu mostro a situação que estava na aula anterior, que eu estava expondo os dados, estou caribando os dados que estão expostos porque eu tenho uma variável na classe "B" "x" que é privada, mas eu estou expondo esses dados através do "get(x)" e o "set(x)", o "get(x)" para obter o valor do "x" e o "set(x)" comparando aquele valor para alterar o valor de x. Eu estou expondo esse dado externamente, então no meu caso ali da classe "A", ele está querendo incrementar o valor de "B". Incrementar o valor de "B" significa você, no caso aí é incrementar por 1 apenas, significa você obter o sucessor. Então o que é que ele faz agora? Antes, ele vai obter o "x" na lógica ali de método da classe "A", ele obtém o "x", soma de 1, que é o sucessor, e manda que o objeto da classe "B" armazene o novo valor do sucessor "B". Pronto, isso não é uma coisa boa. Eu estou expondo os dados. Então, como é que eu resolvo isso usando o príncipio "Tell, don't ask!"? Agora nós vamos então, o que é que a classe "A" quer? É o sucessor do dado exposto por "set(x)" e "get(x)". Então quando eu falo que quero incrementar o valor de "B" é apenas por 1, então, lá na lógica do método de "A" eu tenho lá o "b.setX(b.getX( ) + 1", eu fui lá, obtive o valor de "x" do objeto "B" e somo de 1, o sucessor". Então, qual é que é a solução agora? Eu não quero deixar isso exposto. Então o que é que eu faço primeiramente? Essa responsabilidade de calcular o sucessor, eu transfiro para a classe "B". Então, lá na classe "B" vai ter uma responsabilidade que é o sucessor e que vai fazer exatamente isso que eu estou fazendo aqui dentro do método da classe "A". O lugar mais apropriado para fazer é lá "B", porque "B" tem a informação. Então eu vou ordenar que "B" me dê o sucessor ,e a lógica do sucessor é aquilo que eu estava usando atualmente, e eu vou passá-la para "B". Então a lógica inclusive, já está pronta. Então vejam que a classe "B", agora tem método público que é o sucessor. Os métodos "get(x)" e "set(x)" que antes eram públicos, agora eu deixo eles como protegidos. Vou explicar isso daqui a pouco. Eu deixo protegido, de forma a que externamente, o objeto da classe "B" não expõe mais o dado. A única forma de alterar o "x" é na hora que eu crio objeto "B", pelo construtor "B", ou na hora de passar a mensagem sucessor para objeto "B". Como a gente está vendo aí, aquela operação que eu fazia no método de "A", agora estou fazendo dentro do método do sucessor. Ele é público porque a classe "A", o método da classe "A" tem agora o sucessor como colaboração. Dê uma olhada aí na classe "A" no "Antes" que o método da classe "A" tinha lá como comentário "Incrementa o valor de b!" que é de 1, e isso significa o sucessor e a expressão toda com que eu calculo isso. Então, eu tenho lá duas dependências do método "A" relação ao método "B" que é o "set(x)" e o "get(x)". Bom, depois, usando o princípio do "Tell, don't ask!". Eu simplesmente não preciso nem colocar comentário porque fica claríssimo. Eu estou com o objeto "B" e mando calcular o sucessor, só isso. Já está claro. Nem comentário se torna necessário. Como sucessor eu coloquei como público lá "B" e eu tenho acesso aqui "A". Olhando agora o todo, dá para ver que a classe "A", o método da classe "A", agora só tem uma dependência relação ao método sucessor. É uma colaboração do método sucessor da classe "B". Antes, eu tinha duas, então, a redução foi de 50%. Eu tinha apenas método, mas imagine que se eu tivesse por exemplo, vários métodos de diversas classes que usassem esse método sucessor da classe "B". Pelo esquema anterior todo o cálculo tinha que ser feito cada desses lugares diferentes, tendo o código redundante. Agora, tendo passado para o lugar certo, que é a classe "B", além de não expor os dados internos usando "get(x)" e "set(x)" eu reduzi o acoplamento 50%, que é uma coisa brutal quando eu tenho mais redundância. Quando tenho uma não fica muito expressivo, mas eu posso imaginar que eu poderia ter muitos lugares querendo usar esse sucessor. Na modelagem "CRC", o princípio "Tell, don't ask!" que nós estamos agora apresentando, já deve fazer parte quando você está modelando a lógica das responsabilidades. Vocês viram que isso é importante, porque eu reduzo o acoplamento, eu reduzo a exposição de dados internos deste tipo, usando "getters e setters" como eu mostrei. Então, é muito importante aplicar isso na hora que eu estou fazendo a definição da lógica das responsabilidades a qualquer momento, a qualquer momento que eu esteja precisando definir ou redefinir a lógica, eu vou sempre pensar nisso. Porque essa é uma maneira orientada a objetos, verdadeiramente orientada a objetos e não podemos deixar de fazer uso disso, se isso vai tornar o meu programa, a minha aplicação, menos acoplada, mais flexível e com mais qualidade. Quero ressaltar que a aplicação desse princípio Tell, don´t ask, normalmente a gente faz com as responsabilidades do tipo faz! Porque as responsabilidades do tipo Sabe elas são muito simples. A implicação que vai ter, vai ser com relação a quando eu estiver traduzindo uma responsabilidade do tipo Sabe, Getters ou Setters e eventualmente eu já vou definir esses getters e setters como protegidos. A outra coisa é que usando esse princípio, você naturalmente vai distribuindo mais a inteligência, as funcionalidades, através das classes. Porque você vai atribuir as responsabilidades às classes mais apropriadas. No caso aqui, nesse exemplo, era a classe que continha uma informação. Vez de eu buscar essa informação e trazer pra mim, eu simplesmente ordeno para esse lugar que tem essa informação, para fazer o que eu quero. A consequência, como nós vimos, é a diminuição do acoplamento entre as classes. Para esse tipo de acoplamento, que é considerado entre os piores, que os dados internos ficam expostos, ou diretamente, ou através de getters e setters, isso no nosso caso, a gente diminui 50%. A outra coisa é que você também diminui a necessidade de getters e setters públicos. Poucos casos serão necessários ter getters e setters públicos. Por exemplo, classes que são repositórios de dados, muitas vezes você é obrigado a ter getters e setters para obter alguma informação, porque eles é repositórios de dados. O livro por exemplo, você às vezes quer saber alguma informação sobre o livro, se ele está disponível ou não. Para isso você vai obter essa informação. Ou seja, ela naturalmente vai aparecer na minha modelagem CRC. A consequência é que a maioria dos getters e setters, os getters que também são chamados de métodos de acesso que os getters você acessa a informação, dado de variáveis de instância. O setters é que modificam, é uma edição chamadas de Mutators. A maioria dos getters e setters vão ser protegidos. Por convenção, quando eu estiver pensando colocar getters e setters, eu coloco eles como protegidos. No Java, isso vai aparecer como Protected, eu vou dizer que ou então UML, representando o Jogo da Velha, o Hash. Como vocês lembram, quando eu mostrei na classe B anteriormente, o Get X e Set X eu representei ele no depois, já com esse Hash, com esse Jogo da Velha, indicando que eles já são protegidos. O que significa ser protegido? Não tem acesso externo do objeto, só internamente. Eu poderia ter colocado como privado, se eu quisesse. Mas porque eu coloco como protegido? Eu coloco como protegido porque eu quero permitir o acesso a objetos de subclasses da classe do qual esse getter e setter foram definidos. Por isso eu coloco como protegido. Normalmente, o protegido, essa forma de acesso Protected, não vai acontecer de outra forma, só vai acontecer normalmente, para getters e setters e por causa do uso subclasse. Porque é que a subclasse eu preciso ter isso protegido no getter e setter? Porque o getter e setter está permitindo o acesso às variáveis de instância da classe. Por convenção, nós estamos e pelo princípio do encapsulamento, nós estamos colocando que as variáveis de instância são sempre, sempre, privadas. Sinalzinho negativo na UML, Private no Java. O que significa isso? Se eu criar uma subclasse dessa classe, a variável de instância não vai ser transmitida como herança para a subclasse. Mas eu quero usar isso, como é que eu faço isso? Nessa hora é que eu vou usar os métodos de acesso protegidos. Então o método de acesso, basicamente, é para permitir o acesso às variáveis de instância por subclasse, não externamente, embora alguns casos, como eu falei, algumas classes do tipo repositórios de dados, eles vão ter getters e setters públicos ou normalmente, pelo menos getters públicos. Alguns Frameworks você usa por exemplo, Hybernate para banco de dados, armazenar, ele exige que todos os seus getters e setters sejam públicos então você vai colocar os seus getters e setters, nesse caso, do Hybernate, como públicos, mas você vai estar pensando que eles são protegidos. Você só está colocando eles como públicos, para ser usado pelo Framework Hybernate. Mas nenhum outro momento você vai usar esses getters e setters, porque se não você está expondo os dados. A não ser se fosse repositório de dados, como a gente acabou de falar. Com isso, mostramos para vocês, exemplo de aplicação do princípio Tell, Don't Ask e as consequências que isso tem, nós aplicamos para o getter e setter e mostramos as consequências que isso tem no fato de o getter e setter serem até terem o acesso protegido. Obrigado. [MÚSICA] [MÚSICA]