Buscar

Além da criação da fábrica, é preciso substituir os locais onde a classe StatusItem é instanciada pela invocação da fábrica. Uma forma de ajudar a ...

Além da criação da fábrica, é preciso substituir os locais onde a classe StatusItem é instanciada pela invocação da fábrica. Uma forma de ajudar a detectar esses pontos é declarar o construtor da classe com o modificador de acesso default, e colocar somente a fábrica no mesmo pacote que ele. Isso gerará um erro de compilação em todas as classes fora desse pacote que tentarem utilizá-lo. Casa do Código Capítulo 9. Gerenciando Muitos Objetos Cuidados para Criar Objetos Imutáveis e Únicos Criar classes que geram objetos imutáveis pode não ser algo tão trivial quanto se imagina. Principalmente em linguagens orientadas a objetos em que as classes podem ser estendidas e comportamentos podem ser sobrepostos. Na implementação do Flyweight é importante ter certeza de que as instâncias compartilhadas realmente não permitem modificação, pois isso poderia resultar em um problema crítico e difícil de detectar. Abaixo estão algumas diretivas a serem seguidas para a implementação de classes imutáveis: • Não adicione métodos setter ou outros métodos que modifiquem os atributos da classe. Isso irá impedir que externamente os clientes do objeto o modifiquem. • Crie todos os atributos como private e final. Isso irá impedir que eles sejam inacessíveis a subclasses e que possam ser modificados após a sua primeira atribuição de valor. • Impeça a criação de subclasses. Isso pode ser feito de forma direta declarando a classe como final. Outra alternativa é declarar o construtor como private e utilizar um Static Factory Method para a criação das instâncias. Isso é importante para impedir que subclasses adicionem novas características mutáveis. • Não retorne diretamente atributos com objetos mutáveis. Em outras palavras, se você retornar um objeto mutável armazenado em um atributo, ele poderá ser modificado pelos clientes, mesmo estando definido como final. Caso seja mesmo necessário retorná-lo, crie uma cópia e o retorne. • Cuidado ao receber objetos mutáveis na construção do objeto, pois eles podem ser modificados pelos clientes posteriormente, mesmo não sendo retornados pela classe. O que recomenda-se nesse caso é a criação de uma cópia do objeto mutável recebido para o armazenamento em um atributo do objeto imutável. Analisando a classe StatusItem apresentada anteriormente, é possível observar que ela não segue todas as recomendações para a criação de objetos imutáveis. Apesar de não possuir métodos setter para modificações no objeto, os atributos não possuem o modificador final e a classe pode ser estendida. A listagem a seguir mostra a classe StatusItem modificada segundo as recomendações para objetos imutáveis. Observe que o construtor foi definido como privado e foi definido um Static Factory Method para impedir que sejam definidas subclasses. Como nenhum dos atributos dessa classe é mutável, não foi preciso se preocupar com o retorno e com o recebimento deles como parâmetro. Listagem 9.10 - Tornando a classe StatusItem imutável: public class StatusItem { private final String nome; private final boolean podeCancelar; private final boolean compraConcluida; static void StatusItem criar(String nome, boolean podeCancelar, boolean compraConcluida) { return new StatusItem(nome, podeCancelar, compraConcluida); } private StatusItem(String nome, boolean podeCancelar, boolean compraConcluida) { this.nome = nome; this.podeCancelar = podeCancelar; this.compraConcluida = compraConcluida; } //métodos de acesso as propriedades } Um outro cuidado que é preciso ter seria em relação à unicidade dos objetos do Flyweight. Além da existência da fábrica, é preciso ter certeza de que ela está sendo invocada em todos os locais onde o objeto é criado. Na classe StatusItem dessa seção, o Static Factory Method chamado criar() é definido com o modificador de acesso default para que somente a fábrica, localizada no mesmo pacote que ele, possa utilizá-lo. Porém, somente isso pode não ser suficiente para garantir essa unicidade. Um caso que precisa de um tratamento especial é quando a classe que contém o Flyweight precisa ser serializada. Normalmente isso ocorre quando ela é enviada remotamente como parâmetro ou quando é persistida em um arquivo. Nesse caso, no momento da desserialização uma nova instância do Flyweight será criada. Nesses casos, é preciso sobrepor o mecanismo de serialização da classe que contém a instância do Flyweight para que ela seja recuperada da fábrica quando for desserializada. Para exemplificar esse caso, será considerada a classe Item que é composta pela classe StatusItem, e no exemplo precisa ser serializável pois é enviada remotamente como parâmetro para um EJB. Para evitar que um atributo do tipo StatusItem seja incluído de forma inadequada em uma classe serializável, ela deve ser mantida sem a implementação da interface Serializable. Dessa forma, caso haja a tentativa de serializá-la, mesmo que dentro de uma outra, ocorrerá um erro. Para que seja possível serializar uma classe composta por um StatusItem, é necessário declarar o atributo como transient para que ele não seja incluído no algoritmo de serialização. Em seguida é preciso customizar o algoritmo de serialização para que ele de alguma forma guarde o status do objeto e o recupere da fábrica depois. Isso pode ser feito criando os métodos privados writeObject() e readObject() na classe. No método writeObject(), o método defaultWriteObject() é chamado para que o algoritmo de serialização padrão seja executado e em seguida o nome do status, que é utilizado para a recuperação da fábrica, também é armazenado. De forma similar, no método readObject(), o método defaultReadObject() é chamado inicialmente e em seguida é lida a string com o nome do status. Essa string é utilizada para recuperar o StatusItem da fábrica e o atribuir ao atributo da classe. Listagem 9.11 - Sobrepondo o mecanismo de serialização da classe Item: public class Item implements Serializable { private transient StatusItem status; //outras propriedades //métodos getters e setters omitidos private void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); oos.writeObject(status.getNome()); } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); String status = ois.readObject().toString(); this.status = FabricaStatusItem.getInstance().get(status); } 9.4. Reaproveitando Instâncias com Flyweight Casa do Código O código da listagem a seguir pode ser utilizado para testar se o mecanismo de serialização está funcionando corretamente. O método chamado copiarPorSerializacao() cria uma cópia do objeto a partir de sua serialização e desserialização. Dessa forma, é possível criar um objeto da classe Item, criar uma cópia e em seguida verificar se a instância configurada na variável transiente, que no caso representa o Flyweight, é a mesma. Listagem 9.12 - Sobrepondo o mecanismo de serialização da classe Item: public class TesteSerialização { public static void main(String[] args) throws Exception { Item i1 = new Item(); i1.setProduto("Livro Design Patterns"); i1.setStatus(FabricaStatusItem.getInstance().get("PAGO")); //seta outras propriedades Item i2 = (Item) copiarPorSerializacao(i1); if(i1.getStatus()==i2.getStatus()){ System.out.println("Mesma instância!"); } } public static Serializable copiarPorSerializacao(Serializable obj) throws Exception { ObjectOutputStream output = null; ObjectInputStream input = null; try { ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(); output = new ObjectOutputStream(byteOutput); output.writeObject(obj); output.flush(); byte[] byteArray = byteOutput.toByteArray(); ByteArrayInputStream byteInput = new ByteArrayInputStream(byteArray); input = new ObjectInputStream(byteInput); return (Serializable) input.readObject(); } finally { output.close(); input.close(); } face entre elas. Quando o número de instâncias é muito grande, é importante gerenciar o relacionamento entre elas para que seja possível entender o estado do sistema em um determinado momento. O padrão Facade foi apresentado como uma forma de dividir a aplicação em subsistemas. Ele cria uma interface única que coordena a invocação de diversas classes para fornecer serviços ao resto da aplicação. Como consequências principais, as classes encapsuladas ficam desacopladas do resto da aplicação, e a interface para obter sua funcionalidade é simplificada. De forma similar, o Mediator serve como um intermediário para relação entre objetos do sistema. Por centralizar e gerenciar os relacionamentos, o mediador retira das classes essa responsabilidade que fica espalhada entre elas e desacopla a classe que gera uma chamada de método da classe que a recebe. Em seguida, focando na diminuição do número de instâncias similares de uma mesma classe, o Flyweight propõe que essas instâncias sejam reaproveitadas em diversos pontos da aplicação. Para isso, é preciso criar uma fábrica desses objetos, a qual retorne a mesma instância quando forem necessários objetos similares. Também é preciso que essa classe compartilhada seja imutável, para que alterações realizadas em um contexto não afetem outros em

Essa pergunta também está no material:

Design Patterns com Java - Projeto orientado a objetos guiado por padrões - Casa do Codigo
274 pág.

Português Escola Colegio Estadual Barao Do Rio BrancoEscola Colegio Estadual Barao Do Rio Branco

Respostas

User badge image

Ed Verified user icon

Parece que sua pergunta está incompleta. Você precisa criar uma nova pergunta.

0
Dislike0

Responda

SetasNegritoItálicoSublinhadoTachadoCitaçãoCódigoLista numeradaLista com marcadoresSubscritoSobrescritoDiminuir recuoAumentar recuoCor da fonteCor de fundoAlinhamentoLimparInserir linkImagemFórmula

Para escrever sua resposta aqui, entre ou crie uma conta

User badge image

Mais conteúdos dessa disciplina