State: diferenças entre revisões

9 364 bytes adicionados ,  12h34min de 8 de maio de 2012
sem resumo de edição
[[File:State.png | right | Diagrama UML Pattern Design State]]
{{Reciclagem|data=Fevereiro de 2008}}
 
'''''State''''' é um [[padrão de projeto de software]] usado quando o comportamento de um objeto muda, dependendo do seu estado. Por exemplo, um alarme pode estar em diferentes estados: como desligado, ligado ou em configuração. Definimos una interfaz Estado_Alarma, y luego definimos los diferentes estados.
 
== Introdução ==
O padrão State deve ser utilizado nas seguintes situações:
 
Em certas ocasiões, quando o contexto em que está a desenvolver requer um objeto que possue comportamentos diferentes dependendo de qual estado se encontra, é difícil manejar a mudança de comportamento e os estados desse objeto, tudo dentro do mesmo bloco de código. O padrão State propõe uma solução para esta complicação, criando basicamente, um objeto para cada estado possível do objeto que o chama.
 
== Objetivo ==
 
Permite que um objeto altere seu comportamento de acordo com o estado interno que se encontra em um momento dado.
 
== Motivação ==
[[File:TCPconexion.png| right | Diagrama UML TCPConexion]]
O padrão State é motivado por aqueles objetos que, em seu estado atual, varia o seu comportamento devido as diferentes mensagens que possa receber.
Como exemplo, tomamos uma classe TCPConection que representa uma conexão de rede, um objeto desta classe terá respostas diferentes, dependendo da seu estado(Listening, Close o Established). Por exemplo invocando o método Open de um objeto da classe TCPConection seu comportamento será diferente, se a conexão está no estado Close o em Established.
 
== Problema ==
 
Há uma extrema complexidade no código quando tentar gerir comportamentos diferentes, dependendo de um número de estados diferentes. Também manter o código torna-se difícil, e mesmo em alguns casos, podem apontar para a inconsistência de estados atuais na forma de implementação dos diferentes estados no código (por exemplo, com variáveis ​​para cada estado).
 
== Considerações ==
 
Devemos analisar a complexidade em comparação com outras soluções.
 
== Solução ==
 
Se implementa uma classe para cada estado diferente do objeto e o desenvolvimento de cada método para cada estado em particular. O objeto da classe a que pertencem esses estados resolvem os diferentes comportamentos, dependendo de sua condição, com as instâncias das classes de estado. Assim, sempre está presente em um objeto o seu estado atual e se comunica com ele a resolvendo suas responsabilidades.
 
A idéia principal do padrão State é a introdução de um [[classe abstrata]] TCPState que representa os estados da conexão de rede e uma interface para todas as classes que representam os próprios estados. Por exemplo, as classes TCPEstablished e TCPClose implementam responsabilidades especiais para os estados Established e Close respectivamente do objeto TCPConnection.
A classe TCPConnection mantém uma instância de alguma subclasse de TCPState com o atributo state que representa o estado actual da conexão. Na implementação dos métodos de TCPConnection haverá chamadas a esses objetos que serão representados pelo atributo state para a execução das responsabilidades, dependendo de qual estado se encontre en esse momento, enviará essas chamadas para um objeto ou outro das subclasses de TCPState.
 
== Estrutura UML ==
 
== Os participantes ==
 
#'''Context (Contexto):''' Este integrante define a interface com o cliente. Mantém uma instância de ConcreteState (Estado Concreto) que define seu estado atual.
#'''State (Estado):''' Define uma interface para encapsular as responsabilidades associadas a um estado particular de context.
#'''Subclasse ConcreteState:''' Cada uma dessas subclasses implementa o comportamento ou responsabilidade de Context.
 
O Contexto (Context) delega o estado específico para o objeto ConcreteState atual. Um objeto de Context pode passar-se como parâmetro a um objeto State. Assim, a classe State pode acessar o contexto, se fosse necessário.
Context é a interface principal para o cliente. O cliente pode configurar um contexto com objetos State. Uma vez feito isso, os clientes não têm de lidar com objetos de State diretamente. Tanto o objeto de Context como os objetos de ConcreteState podem decidir a mudança de estado.
 
== Colaborações ==
 
O padrão de State pode usar o padrão [[Singleton (padrão de design) | Singleton]] quando necesita a existe de apenas uma instância de cada estado. Se pode utilizar quando se compartem os objetos como Flyweight existindo uma única instância de cada Estado e esta é compartilhada com mais de um objeto.
 
== Como funciona ==
 
A classe Context envia mensagens para os objetos de ConcreteState dentro de seu código para dar a estes a responsabilidade que deve ser cumplida pelo objeto Context. Então, objeto Context vai mudando as responsabilidades de acordo com o estado em que se encontra, devido a que também muda de objeto ConcreteState ao fazer a mudança de estado.
 
== Quando usá-lo? ==
 
Está recomendado quando um determinado objeto tem estados e responsabilidades diferentes, dependendo de qual estado você está em determinado momento.
Também pode ser usada para simplificar os casos em que há código complicado e extenso de decisão que depende do estado do objeto
 
== Vantagens e desvantagens ==
 
São as seguintes vantagens:
* É fácil de localizar as responsabilidades de estados específicos, devido a que os encontram nas classes que correspondem a cada estado. Isto proporciona uma maior clareza no desenvolvimento e na manutenção subsequente. Esta facilidade é fornecida pelo fato de que diferentes estados são representados por um único atributo (State) e não envolvidos em diferentes variáveis ​​e grandes condicionais.
* Faz as mudanças de estado explícitas, posto que em otro tipo de implantação os estados são alterados, modificando os valores em variáveis, enquanto aqui fazer-se representar cada estado.
* Os objetos State podem ser compartilhados se eles não contêm variáveis ​​de instância, isto pode ser alcançado se o estado está totalmente codificado representando seu tipo. Quando isso é feito, os estados são flyweights sem estado intrínseco.
* Facilita a expansão de estados
* Permite a um objeto alterar de classe em tempo de execução dado que ao modificar suas responsabilidades pela de outro objeto de outra classe, a herança e responsabilidades do primeiro mudaram pelas do segundo.
 
Desvantagem:
* Aumenta o número de subclasses.
 
= Implementación (Java) =
<source lang="java5">
public class Test
{
public static void main( String arg[] )
{
try
{
State state = new ConcreteStateA();
Context context = new Context();
context.setState( state );
context.request();
}
catch( Exception e )
{
e.printStackTrace();
}
}
}
</source>
 
<source lang="java5">
public class Context
{
private State state;
public void setState( State state )
{
this.state = state;
}
public State getState()
{
return state;
}
public void request()
{
state.handle();
}
}
</source>
 
<source lang="java5">
public interface State
{
void handle();
}
</source>
 
<source lang="java5">
public class ConcreteStateA implements State
{
public void handle()
{
}
}
public class ConcreteStateB implements State
{
public void handle()
{
}
}
</source>
 
<source lang="java5">
/**
* State patter:We have a specific class(Context) that manages the state changes of a external class by creating different instance depending
* on the state you want to adopt.
* Every class that you create implements an interface(State) that define the method name that they have to implement
* @author Pperez
*
*/
 
public class StatePattern {
public void main(String args[]){
try{
State state;
Context context = new Context();
SocketChannel socketChannel = null;
//-----------------------------\\
// OPEN/LISTENING SOCKET \\
//-----------------------------\\
//First State:
state = new ConnectSocketState(socketChannel);
context.setState( state );
socketChannel = context.request();
//-----------------------------\\
// CLOSE SOCKET \\
//-----------------------------\\
//Second State:
state = new CloseSocketState(socketChannel);
context.setState( state );
socketChannel = context.request();
}catch( Exception e ) {
e.printStackTrace();
}
}
 
public class Context
{
private State state;
public void setState( State state )
{
this.state = state;
}
public State getState()
{
return state;
}
public SocketChannel request()
{
return state.processState();
}
}
 
public interface State
{
SocketChannel processState();
}
 
public class ConnectSocketState implements State
{
SocketChannel socketChannel;
public ConnectSocketState(SocketChannel socketChannel){
this.socketChannel=socketChannel;
}
public SocketChannel processState()
{
try {
int port = 21;
InetAddress host = InetAddress.getByName("192.168.1.1");
SocketAddress adress = new InetSocketAddress(host, port);
socketChannel = SocketChannel.open(adress);
socketChannel.configureBlocking(true);
} catch (IOException e) {
e.printStackTrace();
}
return socketChannel;
}
}
public class CloseSocketState implements State
{
SocketChannel socketChannel;
public CloseSocketState(SocketChannel socketChannel){
this.socketChannel=socketChannel;
}
public SocketChannel processState(){
try {
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
return socketChannel;
}
}
 
 
}
</source>
 
== Conclusões ==
O comportamento de um objeto depende fortemente do seu estado e ele deve alterar o seu comportamento em tempo de execução dependendo do estado. Os métodos têm instruções condicionais grandes em que as condições dependem do estado do objecto. Este estado é normalmente representado por uma ou mais constantes do tipo enumerado. Frequentemente, vários métodos contém esta mesma estrutura condicional.
O padrão State coloca cada ramo da instrução condicional numa classe separada. Desta forma, o estado do objecto pode ser tratado como um objecto ele próprio, o qual pode variar.
 
O padrão não indica exatamente donde definir as transições de um estado para outro. Há duas maneiras de contornar isso: Uma delas é definir essas transições dentro da classe Context, a outra é definir essas transições nas subclasses de State. É mais conveniente utilizar a primeira solução quando o critério a ser aplicado é fixo, ou seja, não mudará. O segundo é conveniente quando este critério é dinâmico, a desvantagem aqui é apresentada na dependência de código entre as subclasses.
{{esboço}}
 
Precisamos também avaliar a implementação ao criar instancias de estado concreto diferentes ou usar a mesma instância compartilhada. Isto irá depender se a mudança de estado é menos frequente ou mais frequente, respectivamente.
{{Padrões de projeto}}
 
[[Categoria:Programação orientadaDesign a objetosPatterns]]
[[Categoria:Padrões de projeto de software]]
 
[[bg:Състояние (шаблон)]]