Padrão State: Singleton ou Enum?

Saudações aos colegas dos forum…

Estou com um dúvida criada com a reportagem ProfessorJ: Enums Desmistificadasda mundo java desse bimestre.
Uma vez que as Enums que contenham métodos associadas a constantes (e eu acho que as que não tenham também são) são singletons existe alguma vantagem, seja ela conceitual ou de desempenho, quando se opta pelas Enums, ao invés, de Classes Singletons para compor o padrão STATE?

Desde já agradeço!

Como o enum é só um sintax suggar para um grupo de classes singletons com um ancestral em comum, acho que não. Nem para o state, nem para o strategy. A vantagem é que alguns métodos realmente práticos, como o values(), name() e valueOf() já estão implementados para você.

[quote=maruero]Saudações aos colegas dos forum…

Estou com um dúvida criada com a reportagem ProfessorJ: Enums Desmistificadasda mundo java desse bimestre.
Uma vez que as Enums que contenham métodos associadas a constantes (e eu acho que as que não tenham também são) são singletons existe alguma vantagem, seja ela conceitual ou de desempenho, quando se opta pelas Enums, ao invés, de Classes Singletons para compor o padrão STATE?
[/quote]

1)Enum não são singleton, isso é uma antitese ( enum=vários objetos , singleton =1 objeto)
2) Não é possivel implementar State com singleton ( a menos que seja um só estado, e um sistema mono-estado não é um sistema interessante)
3) Enum é em si mesmo um padrão. Ele pode ser usado para implementar state mas não é esse o objetivo primário do padrão.
4) Implmentar State com enum é muito simples porque o java já dá as ferramentas mais importantes que são o proprio enumerado de estados. É só acrecentar método de alteração de estado e voilá. Com enum e metodos vc pode mapear um diagrama de estados facilmente. Exemplo


enum EstadoPersistente{

BLANK.
FILLED.
READ,
EDITED.
REMOVED

    public EstadoPersistente save(){
           switch (this){
             case FILLED:
             case EDITED:
                return READ;
             default :
               return this;
           }
    }

   public EstadoPersistente delete(){
           switch (this){
             case BLANK:
             case FILLED:
               return BLANK
             default :
               return REMOVED;
           }
    }

}

Antes de mais nada, por que implementar um Singleton em primeiro lugar?

Depois, supondo que você implemente state no Singleton, ter um singleton com estado não é problema mas é uma escolha de design bem estranha. Se você implementar o estado em si como um Singleton faz mais sentido mas ainda cai na primeira pergunta: para que um Singleton?

Cada enum implementa uma subclasse diferente da classe do seu enum principal. Ele também limita a criação de instancias a somente 1. O que significa que eles são uma espécie de singleton sim, mas com uma classe abstrata ancestral comum.

É possível sim. Basta que cada classe Singleton tenha uma interface em comum. É o que demonstra o Mat Buckland em seu livro de IA. Entretanto, isso é válido apenas quando cada objeto não guarda estado. O uso de singletons por si só é controverso, especialmente em Java.

Isso é verdade.

Vocë também pode usar polimorfismo nos enum, ao invés do switch, como eu fiz aqui:
http://www.guj.com.br/posts/list/55885.java

Isso facilita ainda mais o uso do padrão state.

Além disso, usar o state com classes a vantagem de que você pode carregar estados de um arquivo, como uma linguagem de script. Isso torna a sua ferramenta flexível, mas nem sempre é necessário.
2.

Cada enum implementa uma subclasse diferente da classe do seu enum principal. Ele também limita a criação de instancias a somente 1. O que significa que eles são uma espécie de singleton sim, mas com uma classe abstrata ancestral comum.
[/quote]

não quero bater na tecla do singleton outra vez, mas qualque classe que tenha mais do que uma instancia não é singleton
Ou seja, variáveis de classes sigleton nunca são polimorficas. Enum criar variáveis polimorficas.
Eu não conhecia essa implementação de classe abstrata, mas o proprio facto dela ser abstract indica que não é um singleton.

Peço que procurem o padrão Shared Object que é realmente o que as instancias de Enum são. Não são singletons.

bom, eu não li esse livro, mas um objeto de estado que não tem estado não é um objeto de estado para começo de conversas, por conseguinte não é um State. Mesmo que fosse, como disse antes, um sistema mono-estado não é interessante.
(não será que está confundindo com Strategy ? Ai sim, pode ser um singleton)

[quote=sergiotaborda]bom, eu não li esse livro, mas um objeto de estado que não tem estado não é um objeto de estado para começo de conversas, por conseguinte não é um State. Mesmo que fosse, como disse antes, um sistema mono-estado não é interessante.
(não será que está confundindo com Strategy ? Ai sim, pode ser um singleton)[/quote]

O Strategy e o State são mesmo muito parecidos. A diferença está no fato de que cada objeto de um state, por si só, representa um estado e sabe a lógica para trocar de estado. Isso não significa que ele tenha que conter estados internos. Mesmo sem estado interno, ele pode representar o estado de outra classe, que o utiliza.

Um material muito bom sobre esse assunto é esse aqui:
http://www.ai-junkie.com/architecture/state_driven/tut_state1.html

Ele mostra um exemplo de um minerador, cuja máquina de estados utiliza o padrão State, sem que os objetos de estado em si contenham estados internos. Aliás, ele também usa o padrão singleton em cada objeto de estado.

[quote=sergiotaborda]não quero bater na tecla do singleton outra vez, mas qualque classe que tenha mais do que uma instancia não é singleton
Ou seja, variáveis de classes sigleton nunca são polimorficas. Enum criar variáveis polimorficas.
Eu não conhecia essa implementação de classe abstrata, mas o proprio facto dela ser abstract indica que não é um singleton.[/quote]

O problema é que você está olhando para o topo da hierarquia. Se for assim, o Java não tem singleton, pq todas as classes derivam de Object.

No enum, cada item da enumeração é implementado como uma subclasse. Por exemplo, isso:

enum Xyz { A, B, C};

Equivale a:

public abstract class Xyz { public static Xyz A = new XYZ() {} public static Xyz B = new XYZ() {} public static Xyz C = new XYZ() {} }
Note que A, B e C são inner classes de Xyz. E o Java garante que o construtor de todos sejam private. Por isso, muitos autores dizem que A, B e C são singletons, porque cada inner class tem uma única instância.

[quote=ViniGodoy][quote=sergiotaborda]não quero bater na tecla do singleton outra vez, mas qualque classe que tenha mais do que uma instancia não é singleton
Ou seja, variáveis de classes sigleton nunca são polimorficas. Enum criar variáveis polimorficas.
Eu não conhecia essa implementação de classe abstrata, mas o proprio facto dela ser abstract indica que não é um singleton.[/quote]

O problema é que você está olhando para o topo da hierarquia. Se for assim, o Java não tem singleton, pq todas as classes derivam de Object.

No enum, cada item da enumeração é implementado como uma subclasse. Por exemplo, isso:

enum Xyz { A, B, C};

Equivale a:

public abstract class Xyz { public static Xyz A = new XYZ() {} public static Xyz B = new XYZ() {} public static Xyz C = new XYZ() {} }
Note que A, B e C são inner classes de Xyz. E o Java garante que o construtor de todos sejam private. Por isso, muitos autores dizem que A, B e C são singletons, porque cada inner class tem uma única instância.[/quote]

Ao fazer esses 3 new da classe vc está criando três instancias da mesma classe Xyz ( não estou pensando em object).
Vc pode argumentar que como Xyz é abstract então na realidade A, B e C são instancias de classes anonimas. Ok.
Para cada uma dessa classes anónimas existe apenas um objecto. Verdade.
En entendo que considere isso como sigleton , e é isso que eu estou dizendo que não é sigleton

Singleton não é apenas caracterizado por existir uma só instancia, tb por não poder existir nenhuma outra.
Quando vc tem uma só instancia, mas a capacidade de criar outras, mas escolhe instanciar apenas uma, isso é um Shared Object.

O ponto que me referi é que vc pode fazer isto :

Xyz a = Xyz.A
if (a != Xyz.B){
a = Xyz.B
}
System.out.print(a);

Isso vai escrever B e demonstra que a variável ‘a’ é polimorifca.
Ergo, é possivel ter mais do que uma instancia de Xyz simultaneamente

A, B e C são intancias de Xyz. Mesmo que herança ou classes anonimas no meio , continuam sendo instancias de Xyz.
Elas não são instancias de mais nenhum tipo. Mesmo com classes anonimas vc não pode invocar instanceOf para saber o tipo, logo
para todos os efeitos são instancias de Xyx.
Ergo, é possivel ter mais do que uma instancia de Xyz simultaneamente

Portanto, enum não são singleton, QED.

Como disse antes “enum é singleton” é uma antitese. É como “quente é frio”. Singleton tem o objetivo de ter apenas uma instancia possivel enquanto enum tem objetivo de ter várias instancias possiveis : uma para cada item da enumeração , tantas quanto necessário.

Sim, XYZ não é um singleton.

Mas as inner classes são.

Se não for assim, nada em Java é singleton, já que tudo deriva de object e você pode usar polimorficamente o equals, o hascode, ou qualquer método dessa super classe global.

O padrão não diz que uma classe Singleton não pode ter uma superclasse, e que outras classes da hierarquia dessa superclasse devem ser únicos.
Ele só diz que uma classe específica pode ter uma, e somente uma, instância. O que é vale para a Inner Class de X, de Y e de Z. Mas não é válido para a superclasse abstrata XYZ.

Na verdade, é por isso que as visões divergem. O catalogo de padrões de projeto admite pequenas variações de um padrão, e não constitui um modelo matemático rígido.

Mas enfim… é uma discussão sobre um padrão que, especialmente em Java, é muito fácil de ser quebrado. Eu só optaria por usa-lo em sistemas com severas limitações de recursos.

No meu caso, estou usando singleton para implementar os estados do padrao State { disponivel , emprestado } dos exemplares de um sistema de bibliotecas.

A questão inicial foi feita na discussão de como implementar um código bem documentado{ diagrama de classes e afins } e bem legível.
E uma questão importante é que uma dos requisitos não funcionais do projeto é a manutenabilidade. Já se preveu que haverá um adicionamento posterior de novos estados { bloqueado , atrazado , etc. } ( não me pergunte pq nao colocar esses estados agora já… eu fiz essa pergunta ao engenheiro… ele argumentou que poderá haver outros que ele nao consegue prever agora…blablabla… ).

Por esses fatores decidir utilizar o padrão STATE e como nao bem vindo haver 1 instancia dos estados para cada exemplar decidi utilizar tbm o singleton… é essa a idéia de singletons néh!!!

Tinha me esquecido dos debates que o Singleton causavam aqui no forum… mas toda discussão é bem vinda…

ViniGodoy vc tem alguma referencia dizendo que o Enum é um Singleton? A propósito vou olhar na revista também…

Você pode ler a especificação oficial do enum, mas como o Sergio corretamente apontou, não é uma implementação exata do padrão, tal como vista no livro do GoF.

Uma das garantias do Java é que cada item da enumeração será criado uma única vez.

Dá uma lida aqui:
http://java.sun.com/developer/Books/effectivejava/Chapter5.pdf

E veja o item 21.
O enum do Java foi baseado nesse pattern, descrito pelo Joshua Bloch.

O link aponta para o capítulo 5 do Effective Java, primeira edição.