Flyweight

Intenção

Usar compartilhamento para apoiar eficientemente grandes quantidades de objetos de granularidade fina.

Vantagens

Desvantagens

Exemplos

Exemplo #1

Seja um processador de requisições (Request Processor) cuja responsabilidade é receber uma requisição e processá-la sobre a camada de objetos de negócio (Product, Customer) do domínio (domain model). Um objeto Request é criado para representar a requisição, encapsulando sua lógica de execução. Assim, para cada requisição, o correspondente objeto Request deve ser criado para executá-la.  Como não é necessário armazenar o histórico de execução das requisições, é possível ter todos os objetos Request sem estado intrínseco específico da requisição, e compartilhar objetos Request entre requisições do mesmo tipo, diminuindo o overhead de criação e gerenciamento destes objetos, que podem ser muitos.  Para tal, valores específicos da requisição precisam ser modelados como estado extrínseco do objeto Request, sendo passados como parâmetros. A classe RequestFactory contém um pool de gerenciamento de objetos Request. Esses objetos são criados sob demanda no primeiro acesso. 

 

 

  

Diagrama de Classe

Exemplo #1 - Diagrama

Participantes

  • Flyweight (Request)

Declara uma interface através da qual flyweights podem receber e atuar sobre estados extrínsecos.

  • ConcreteFlyweight (EditProductRequest, EditCustomerRequest)

Implementa a interface de Flyweight e acrescenta armazenamento para estados intrínsecos, se houver.

  • FlyweightFactory (RequestFactory)

Cria e gerencia objetos flyweights e garante que eles sejam compartilhados apropriadamente.

  • Client (RequestProcessor)

Mantém referências para os flyweights, neste caso, referências transientes durante o processamento das requisições.

Código



	CommerceFlyweight
	
	
	
	
		
			org.eclipse.jdt.core.javabuilder
			
			
		
	
	
		org.eclipse.jdt.core.javanature
	

eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=11
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=11
Êþº¾71(br/uff/commerce/domain/customer/Customerjava/lang/ObjectidJnameLjava/lang/String;(JLjava/lang/String;)VCode

	()V	
setName(Ljava/lang/String;)VLineNumberTableLocalVariableTablethis*Lbr/uff/commerce/domain/customer/Customer;getId()JgetName()Ljava/lang/String;	
 "!java/lang/String#trim
 %&'isEmpty()Z)"java/lang/IllegalArgumentException+Name is mandatory.
(-	
StackMapTable
SourceFile
Customer.java!	
Y*·*µ*-¶±
	 /*´­/*´°h+Æ
+¶¶$™
»(Y*·,¿*+µ±.	/0
Êþº¾7"2br/uff/commerce/domain/customer/CustomerRepositoryjava/lang/ObjectsoleInstance4Lbr/uff/commerce/domain/customer/CustomerRepository;()VCode	LineNumberTableLocalVariableTablegetSoleInstance6()Lbr/uff/commerce/domain/customer/CustomerRepository;

StackMapTable
thisinsert-(Lbr/uff/commerce/domain/customer/Customer;)Vproduct*Lbr/uff/commerce/domain/customer/Customer;removeupdatefindById-(J)Lbr/uff/commerce/domain/customer/Customer;idJ
SourceFileCustomerRepository.java!
	%³
±

		E²
Ç
»Y·³
²
°
	3*·±

	5±
	5±!
	5±&
	6°+
 !
Êþº¾7`3br/uff/commerce/domain/customer/EditCustomerRequestjava/lang/Objectbr/uff/commerce/request/RequestNAMELjava/lang/String;
ConstantValueeditCustomer()VCode

LineNumberTableLocalVariableTablethis5Lbr/uff/commerce/domain/customer/EditCustomerRequest;execute(Ljava/util/Map;)V
Exceptions(br/uff/commerce/request/RequestException	Signature8(Ljava/util/Map;)V
customerId! 
java/util/Map"#get&(Ljava/lang/Object;)Ljava/lang/Object;%java/lang/Long
')(2br/uff/commerce/domain/customer/CustomerRepository*+getSoleInstance6()Lbr/uff/commerce/domain/customer/CustomerRepository;
$-./	longValue()J
'123findById-(J)Lbr/uff/commerce/domain/customer/Customer;5java/lang/StringBuilder7Customer with id 
49:(Ljava/lang/String;)V
4<=>append-(Ljava/lang/Object;)Ljava/lang/StringBuilder;@ not found.
4B=C-(Ljava/lang/String;)Ljava/lang/StringBuilder;
4EFGtoString()Ljava/lang/String;
9JnameLjava/lang/String
NPO(br/uff/commerce/domain/customer/CustomerQ:setName
'STUupdate-(Lbr/uff/commerce/domain/customer/Customer;)V
parametersLjava/util/Map;Ljava/lang/Long;subject*Lbr/uff/commerce/domain/customer/Customer;LocalVariableTypeTable5Ljava/util/Map;
StackMapTable
SourceFileEditCustomerRequest.java!	

/*·±ÞO+¹À$M¸&,¶,¶0N-Ç »Y»4Y6·8,¶;?¶A¶D·H¿-+I¹ÀK¶M¸&-¶R±*
(48GN!*OOVWCX8YZ[OV\]ý8$N^_
Êþº¾7`1br/uff/commerce/domain/product/EditProductRequestjava/lang/Objectbr/uff/commerce/request/RequestNAMELjava/lang/String;
ConstantValueeditProduct()VCode

LineNumberTableLocalVariableTablethis3Lbr/uff/commerce/domain/product/EditProductRequest;execute(Ljava/util/Map;)V
Exceptions(br/uff/commerce/request/RequestException	Signature8(Ljava/util/Map;)V	productId! 
java/util/Map"#get&(Ljava/lang/Object;)Ljava/lang/Object;%java/lang/Long
')(0br/uff/commerce/domain/product/ProductRepository*+getSoleInstance4()Lbr/uff/commerce/domain/product/ProductRepository;
$-./	longValue()J
'123findById+(J)Lbr/uff/commerce/domain/product/Product;5java/lang/StringBuilder7Product with id 
49:(Ljava/lang/String;)V
4<=>append-(Ljava/lang/Object;)Ljava/lang/StringBuilder;@ not found.
4B=C-(Ljava/lang/String;)Ljava/lang/StringBuilder;
4EFGtoString()Ljava/lang/String;
9JnameLjava/lang/String
NPO&br/uff/commerce/domain/product/ProductQ:setName
'STUupdate+(Lbr/uff/commerce/domain/product/Product;)V
parametersLjava/util/Map;Ljava/lang/Long;subject(Lbr/uff/commerce/domain/product/Product;LocalVariableTypeTable5Ljava/util/Map;
StackMapTable
SourceFileEditProductRequest.java!	

/*·±ÞO+¹À$M¸&,¶,¶0N-Ç »Y»4Y6·8,¶;?¶A¶D·H¿-+I¹ÀK¶M¸&-¶R±*
(48GN!*OOVWCX8YZ[OV\]ý8$N^_
Êþº¾71&br/uff/commerce/domain/product/Productjava/lang/ObjectidJnameLjava/lang/String;(JLjava/lang/String;)VCode

	()V	
setName(Ljava/lang/String;)VLineNumberTableLocalVariableTablethis(Lbr/uff/commerce/domain/product/Product;getId()JgetName()Ljava/lang/String;	
 "!java/lang/String#trim
 %&'isEmpty()Z)"java/lang/IllegalArgumentException+Name is mandatory.
(-	
StackMapTable
SourceFileProduct.java!	
Y*·*µ*-¶±
	 /*´­/*´°h+Æ
+¶¶$™
»(Y*·,¿*+µ±.	/0
Êþº¾7"0br/uff/commerce/domain/product/ProductRepositoryjava/lang/ObjectsoleInstance2Lbr/uff/commerce/domain/product/ProductRepository;()VCode	LineNumberTableLocalVariableTablegetSoleInstance4()Lbr/uff/commerce/domain/product/ProductRepository;

StackMapTable
thisinsert+(Lbr/uff/commerce/domain/product/Product;)Vproduct(Lbr/uff/commerce/domain/product/Product;removeupdatefindById+(J)Lbr/uff/commerce/domain/product/Product;idJ
SourceFileProductRepository.java!
	%³
±

		E²
Ç
»Y·³
²
°
	3*·±

	5±
	5±!
	5±&
	6°+
 !
Êþº¾7br/uff/commerce/request/Requestjava/lang/Objectexecute(Ljava/util/Map;)V
Exceptions	(br/uff/commerce/request/RequestException	Signature8(Ljava/util/Map;)V
SourceFileRequest.java

Êþº¾7(br/uff/commerce/request/RequestExceptionjava/lang/ExceptionserialVersionUIDJ
ConstantValue()VCode

LineNumberTableLocalVariableTablethis*Lbr/uff/commerce/request/RequestException;(Ljava/lang/String;)V

messageLjava/lang/String;
SourceFileRequestException.java!
3*·
±

>*+·±

Êþº¾7^0br/uff/commerce/requestprocessing/RequestFactoryjava/lang/ObjectsoleInstance2Lbr/uff/commerce/requestprocessing/RequestFactory;poolLjava/util/Map;	SignatureDLjava/util/Map;()VCode	LineNumberTableLocalVariableTablegetSoleInstance4()Lbr/uff/commerce/requestprocessing/RequestFactory;

StackMapTable
java/util/HashMap
	this
createRequest5(Ljava/lang/String;)Lbr/uff/commerce/request/Request;
"$#java/lang/String%&trim()Ljava/lang/String;
"()*isEmpty()Z,"java/lang/IllegalArgumentException.Request name is mandatory.
+01(Ljava/lang/String;)V354
java/util/Map67get&(Ljava/lang/Object;)Ljava/lang/Object;9br/uff/commerce/request/Request;editProduct
"=>?equals(Ljava/lang/Object;)ZA1br/uff/commerce/domain/product/EditProductRequest
@DeditCustomerF3br/uff/commerce/domain/customer/EditCustomerRequest
EIjava/lang/StringBuilderKRequest object not found for 
H0
HNOPappend-(Ljava/lang/String;)Ljava/lang/StringBuilder;
HRS&toString3UVWput8(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;requestNameLjava/lang/String;result!Lbr/uff/commerce/request/Request;
SourceFileRequestFactory.java!
	

%³±	
E²Ç
»Y·³²°
B*·*»Y·µ± 
ùx+Æ
+¶!¶'™
»+Y-·/¿*´+¹2À8M,ÇO+:¶<™»@Y·BM§/+C¶<™»EY·GM§»+Y»HYJ·L+¶M¶Q·/¿*´+,¹TW,°6
#$&&(**3+>,G-R/V0f/j2v6 xxXY&RZ[
	ü%8\]
Êþº¾7:2br/uff/commerce/requestprocessing/RequestProcessorjava/lang/ObjectsoleInstance4Lbr/uff/commerce/requestprocessing/RequestProcessor;factory2Lbr/uff/commerce/requestprocessing/RequestFactory;()VCode	
LineNumberTableLocalVariableTablegetSoleInstance6()Lbr/uff/commerce/requestprocessing/RequestProcessor;


StackMapTable

0br/uff/commerce/requestprocessing/RequestFactory4()Lbr/uff/commerce/requestprocessing/RequestFactory;	thisprocess$(Ljava/lang/String;Ljava/util/Map;)V
Exceptions#(br/uff/commerce/request/RequestException	SignatureJ(Ljava/lang/String;Ljava/util/Map;)V
'()
createRequest5(Ljava/lang/String;)Lbr/uff/commerce/request/Request;+-,br/uff/commerce/request/Request./execute(Ljava/util/Map;)VrequestNameLjava/lang/String;
parametersLjava/util/Map;request!Lbr/uff/commerce/request/Request;LocalVariableTypeTable5Ljava/util/Map;
SourceFileRequestProcessor.java!
	
%³±	E²Ç
»Y·³²°
>*·*¸µ± !"$%s*´+¶&N-,¹*±"	#$*0123	4562789
package br.uff.commerce.domain.customer;

public class Customer
{
	private long id;
	private String name;
	
	public Customer(long id, String name)
	{
		this.id = id;
		this.setName(name);
	}
	
	public long getId()
	{
		return this.id;
	}
	
	public String getName()
	{
		return this.name;
	}
	
	public final void setName(String name)
	{
		if (name == null || name.trim().isEmpty())
			throw new IllegalArgumentException("Name is mandatory.");
		
		this.name = name;
	}	

}
package br.uff.commerce.domain.customer;

/**
 * Repositório (persistência) de Cliente
 * Singleton
 *
 */
public class CustomerRepository
{
	private static CustomerRepository soleInstance = null;
	
	public static CustomerRepository getSoleInstance()
	{
		if (CustomerRepository.soleInstance == null)
			CustomerRepository.soleInstance = new CustomerRepository();
		
		return CustomerRepository.soleInstance;
	}
	
	private CustomerRepository()
	{
		
	}
	
	public void insert(Customer product)
	{
		//insere novo cliente
	}
	
	public void remove(Customer product)
	{
		//remove cliente
	}
	
	public void update(Customer product)
	{
	   //atualiza cliente	
	}
	
	public Customer findById(long id)
	{
		//busca e retorna cliente pelo respectivo id
		return null;
	}
}
package br.uff.commerce.domain.customer;

import java.util.Map;

import br.uff.commerce.request.Request;
import br.uff.commerce.request.RequestException;

/**
 * Concrete Flyweight
 *
 */
public class EditCustomerRequest implements Request
{
	public final static String NAME = "editCustomer";

	@Override
	public void execute(Map parameters) throws RequestException
	{
		
		Long customerId = (Long) parameters.get("customerId");
		
		Customer subject = 
				CustomerRepository.getSoleInstance().findById(customerId);
		
		if (subject == null)
			throw new RequestException("Customer with id "+ 
		                                customerId +" not found.");
			
		subject.setName((String) parameters.get("name"));
		
		CustomerRepository.getSoleInstance().update(subject);
		
	}

}
package br.uff.commerce.domain.product;

import java.util.Map;

import br.uff.commerce.request.Request;
import br.uff.commerce.request.RequestException;

/**
 * Concrete Flyweight
 *
 */
public class EditProductRequest implements Request
{
	public final static String NAME = "editProduct";

	@Override
	public void execute(Map parameters) throws RequestException
	{
		
		Long productId = (Long) parameters.get("productId");
		
		Product subject = 
				ProductRepository.getSoleInstance().findById(productId);
		
		if (subject == null)
			throw new RequestException("Product with id "+ 
		                                productId +" not found.");
			
		subject.setName((String) parameters.get("name"));
		
		ProductRepository.getSoleInstance().update(subject);
		
	}

}
package br.uff.commerce.domain.product;

public class Product
{
	private long id;
	private String name;
	
	public Product(long id, String name)
	{
		this.id = id;
		this.setName(name);
	}
	
	public long getId()
	{
		return this.id;
	}
	
	public String getName()
	{
		return this.name;
	}
	
	public final void setName(String name)
	{
		if (name == null || name.trim().isEmpty())
			throw new IllegalArgumentException("Name is mandatory.");
		
		this.name = name;
	}	

}
package br.uff.commerce.domain.product;

/**
 * Repositório (persistência) de Produto
 * Singleton
 *
 */
public class ProductRepository
{
	private static ProductRepository soleInstance = null;
	
	public static ProductRepository getSoleInstance()
	{
		if (ProductRepository.soleInstance == null)
			ProductRepository.soleInstance = new ProductRepository();
		
		return ProductRepository.soleInstance;
	}
	
	private ProductRepository()
	{
		
	}
	
	public void insert(Product product)
	{
		//insere novo produto
	}
	
	public void remove(Product product)
	{
		//remove produto
	}
	
	public void update(Product product)
	{
	   //atualiza produto	
	}
	
	public Product findById(long id)
	{
		//busca e retorna produto pelo respectivo id
		return null;
	}
}
package br.uff.commerce.request;

import java.util.Map;

/**
 * Flyweight
 *
 */
public interface Request
{
	public void execute(Map parameters) throws RequestException;
}
package br.uff.commerce.request;

/**
 * Indica algum problema na execução de uma requisição.
 *
 */
public class RequestException extends Exception
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public RequestException()
	{
		super();
		
	}

	public RequestException(String message)
	{
		super(message);
		
	}

}
package br.uff.commerce.requestprocessing;

import java.util.HashMap;
import java.util.Map;

import br.uff.commerce.domain.customer.EditCustomerRequest;
import br.uff.commerce.domain.product.EditProductRequest;
import br.uff.commerce.request.Request;

/**
 * Factory parametrizado e Singleton.
 *
 */
public class RequestFactory
{
	private static RequestFactory soleInstance = null;
	
	public static RequestFactory getSoleInstance()
	{
		if (RequestFactory.soleInstance == null)
			RequestFactory.soleInstance = new RequestFactory();
		
		return RequestFactory.soleInstance;
	}
	
	private Map pool;
	
	private RequestFactory() 
	{
		this.pool = new HashMap();
	}
	
	public Request createRequest(String requestName)
	{
		if (requestName == null || requestName.trim().isEmpty())
			throw new IllegalArgumentException("Request name is mandatory.");
		
		Request result = this.pool.get(requestName);
		
		if (result == null)
		{
			if (requestName.equals(EditProductRequest.NAME))
				result = new EditProductRequest();
			else if (requestName.equals(EditCustomerRequest.NAME))
				result = new EditCustomerRequest();
			else 
				throw new IllegalArgumentException(
						"Request object not found for "+ requestName);
			
			this.pool.put(requestName, result);
			
		}
		
		return result;
	}
	
}
package br.uff.commerce.requestprocessing;

import java.util.Map;

import br.uff.commerce.request.Request;
import br.uff.commerce.request.RequestException;

/**
 * Singleton
 *
 */
public class RequestProcessor
{
	private static RequestProcessor soleInstance = null;
	
	public static RequestProcessor getSoleInstance()
	{
		if (RequestProcessor.soleInstance == null)
			RequestProcessor.soleInstance = new RequestProcessor();
		
		return RequestProcessor.soleInstance;
	}
	
	private RequestFactory factory;
	
	private RequestProcessor()
	{
		this.factory = RequestFactory.getSoleInstance();
	}
	
	public void process(String requestName, Map parameters) 
			throws RequestException
	{
		Request request = this.factory.createRequest(requestName);
		request.execute(parameters);
	}
	
}
Clique aqui para fazer o download do código completo de implementação deste Design Pattern.

Padrões Relacionados

Este Padrão pode ser usado para resolver os seguintes problemas: