Alguém tem um exemplo específico de uso do padrão Flyweight? [fechadas]

21

Tenho estudado padrões de design e me deparei com o padrão de peso da mosca. Eu tenho tentado ver oportunidades para usar o padrão nos meus aplicativos, mas estou tendo problemas para ver como usá-lo. Além disso, quais são alguns sinais de que um padrão de peso de mosca está sendo usado quando leio o código de outras pessoas?

De acordo com a definição, diz:

Use o compartilhamento para oferecer suporte a um grande número de objetos refinados com eficiência.

Se eu li certo Dicionários e Hashtables podem ser instâncias de pesos de mosca, isso está correto?

Desde já, obrigado.

Jeremy E
fonte
7
Apenas uma pequena anedota sobre os pesos de mosca: uma vez tive que criar arquivos grandes do Excel (até 500k registros, mais de 100 colunas) com uma API de terceiros. Os estilos para as células tornaram-se extremamente intensivos em memória. Portanto, sempre que um estilo era necessário, uma hashtable era verificada se já existia um estilo igual e fornecia apenas uma referência a esse estilo. Essa modificação tornou possível essa exportação. Agora, ter tantos dados no Excel é loucura na minha opinião. Mas os controladores tinham suas macros de análise que queriam manter.
Falcon
9
Comentário: Espero que as pessoas que escrevem livros e artigos sobre padrões e OO cheguem ao mundo real do programador médio e parem de usar o estilo inglês de advogado!
precisa saber é o seguinte
1
"Certa vez, tive que criar arquivos grandes do Excel (até 500k registros, mais de 100 colunas)" - isso não é muito comparado ao que alguns traders são capazes de criar ;-) #
quant_dev 15/09/11
Depois de ler vários desses exemplos, eu pensaria que a compactação de dados na memória seria um excelente local para implementar essa técnica. Obrigado pela ajuda!
Jeremy E
As células da tabela no GWT são pesos livres.
user16764

Respostas:

19

Um exemplo está nas bibliotecas Java. Java possui tipos primitivos (por exemplo int, que é um número inteiro de 32 bits) e invólucros para eles (por exemplo Integer, que envolve int). Existem métodos para " intencaixar " um em um Integere desmarcar um Integerem um int. Os wrappers são necessários porque os tipos primitivos não são objetos e, portanto, não podem, por exemplo, ser usados ​​como chaves em Maps ou colocados em Collections.

O método de boxe usa uma matriz de objetos flyweight como um tipo de cache para Integers correspondente a intvalores entre -128 e 127. Como esses são os valores com maior probabilidade de serem usados ​​como chaves ou colocados em coleções, reduz a alocação e o uso de memória. (Se houver 5000000 Integers representando o valor 0 flutuando, isso usa 5000000 vezes mais memória que a reutilização da instância flyweight).

Peter Taylor
fonte
1
Portanto, o pool interno de strings em C # é outro exemplo do padrão flyweight correto?
Jeremy E
1
@ Jeremy E: Sim, na minha opinião, você pode chamar string internamente de um aplicativo do padrão flyweight, apesar de strings, não se trata apenas de consumo de memória, mas também de eficiência de tempo de execução.
Falcon
Os ponteiros marcados com Objective-C levam isso ao extremo. Inteiros em caixa de até 56 bits e muitas seqüências de caracteres com até seis caracteres, nem são alocados como objetos, mas todas as informações são compactadas no próprio ponteiro de objeto.
precisa saber é o seguinte
9

Gráficos. Normalmente, uma imagem raster (que é a espinha dorsal da maioria dos gráficos de computador no nível do consumidor) é barata em termos de CPU, mas dispendiosa em termos de memória (o que é bom porque a memória é barata, mas a CPU é cara). Se essa imagem rasterizada deve ser repetida várias vezes na renderização de uma interface do usuário maior (de ícones em um aplicativo da GUI do Windows a caracteres de uma fonte em um processador de texto, a texturas nas superfícies de um jogo em 3D), faz muito sentido carregue a imagem na memória uma vez e aponte-a simplesmente usando objetos muito simples que são baratos de fabricar e que, eles próprios, não consomem muita memória. Um sprite, que é simplesmente um ponto no espaço gráfico no qual uma imagem deve ser exibida, é apenas um ponto 3D e um ponteiro de memória para o primeiro pixel da imagem a ser usado. Talvez também inclua as dimensões da parte do arquivo de imagem do sprite a ser usada, em termos gráficos ou de memória. Todas essas informações são muito baratas para mudar, digamos, para alterar a imagem ou o local do sprite, e isso pode ser feito sem carregar uma nova imagem a cada vez, aumentando drasticamente o desempenho do programa subjacente para manipular e exibir as partes apropriadas do imagens apropriadas para renderizar uma "cena" completa da interface do usuário.

KeithS
fonte
3

As Characterinstâncias de intervalo ASCII no Smalltalk são pesos livres.

Quando você avalia algo como Character space, Character class >> #value:executa:

value: anInteger 
    "Answer the Character whose value is anInteger."

    anInteger > 255 ifTrue: [^self basicNew setValue: anInteger].
    ^ CharacterTable at: anInteger + 1.

A variável de classe CharacterTableé inicializada assim:

initialize
    "Create the table of unique Characters, and DigitsValues."
    "Character initializeClassificationTable"

    CharacterTable ifNil: [
        "Initialize only once to ensure that byte characters are unique"
        CharacterTable := Array new: 256.
        1 to: 256 do: [:i | CharacterTable
            at: i
            put: (self basicNew setValue: i - 1)]].
    self initializeDigitValues

Portanto, quando você cria uma String, o intervalo ASCII Characterserá CharacterTablegerado em vez de ser criado sempre.

Frank Shearar
fonte
3

O objetivo do uso do padrão flyweight é evitar a inicialização desnecessária de objetos e, assim, economizar espaço. Conforme definido pelo GOF , um objeto pode ter dois estados, o intrínseco e o extrínseco:

  • Estado intrínseco: é armazenado no peso mosca; consiste em informações independentes no contexto de pesos livres, tornando-as compartilháveis.
  • Estado extrínseco: depende e varia de acordo com o contexto do peso da mosca e, portanto, não pode ser compartilhado. Os objetos do cliente são responsáveis ​​por passar o estado extrínseco para o peso da mosca quando necessário.

Supondo que desejamos desenvolver um aplicativo simples de editor de texto em que cada coluna contenha todas as linhas do texto e a linha possa conter caracteres.

O dilema aqui é como projetar a classe Character. O char cdentro da classe Character deve ser o objeto principal (estado intrínseco). No entanto, um caractere pode ter uma fonte e um tamanho (estado extrínseco); portanto, precisamos armazenar seu estado extrínseco na linha (cliente) e acessá-lo quando necessário. Para esse fim, são criadas duas listas que armazenam as fontes e os tamanhos.

Seguindo o padrão Flyweight, o caractere agora é reutilizável e os objetos estão sendo referenciados a partir de uma lista específica de objetos (o pool de flyweight) que contém todos os símbolos ASCII ( Characterobjetos).

Aqui está o que eu descrevi visualmente:

insira a descrição da imagem aqui

Para imprimir 'olá', Charactersão necessários apenas 4 objetos, em vez de 5. Depois que a fonte é alterada, nenhum novo objeto é necessário; observe que isso não seria possível se tivéssemos armazenado o estado extrínseco na classe Character, por exemplo,

class Character
{
    char c;
    int Size;
    Font font;

    ....
}

A aplicação desse padrão em grandes conjuntos de dados levaria a otimizações significativas na complexidade da memória do aplicativo e na reutilização do objeto.

Menelaos Kotsollaris
fonte