Construção de objetos pré definidos

Ola pessoal
Com java 5 e enum, estava pensando o que seria mais correto para criar objetos pré definidos para serem usados, como os que a classe Color tem.

  1. Fazer igual como Color foi feito, criando variaveis estaticas que instanciam os objetos pré criados (por exemplo Color tem Color.BLUE, Color.RED etc).
  2. Criar um enum para enumerar quais são os meus objetos pré criados, no caso de Color, as cores padrões, parecido com:
   enum DefaultColors {
      RED() {
         public Color get() {
            return new Color(255, 0, 0);
         }
      },
      
      BLUE() {
         public Color get() {
            return new Color(0, 0, 255);
         }
      };

      public abstract Color get();
   }

Meu ponto de vista: não gosto de criar variaveis estáticas da forma como tem criado em Color, se misturam com outras variaveis, se quero criar outra cor padrão tem alterar a classe Color, etc, porém sua utilização é simples:

setColor(Color.RED);

Sobre criar um enum, acho legal, pois seria um enum enumerando as cores padrões, a classe Color fica apenas para representar a cor e não para listar as cores padrões, porém a utilização é mais chata:

setColor(DefaultColor.RED.get());

mas em compensação posso utilizar em switchs, comparar sem precisar de equals, etc

Bem, só joguei uma ideia e queria saber a opinião de vocês, para mim, criando o enum seriam como um builder de objetos cores, eu tenho a possibilidade de criar minha propria cor, mas existe um builder que me cria tudo que preciso de algumas cores.

Pra falar a verdade não gostei do seu “Builder”.

bele, mas você acha correto implementar como Color esta implementado? Como vc implementaria nessa situação:
Tenho uma classe Banco, vamos supor que todos bancos tivessem o mesmo comportamento, a unica coisa diferente entre eles é o valor da taxa que eles cobram para determinados serviços que também são iguais entre eles, sendo que essas taxas nunca na vida vão mudar, o banco A sempre tera essas taxas, da mesma forma que BLUE sempre vai ser BLUE.
Ai eu quero deixar pré configurado todos bancos que atuam no Brasil, para quem quizer usar minha classe de Banco, possa alem de criar seu proprio banco com suas taxas, ter a opção de escolher entre um desses bancos pré criados.

Você faria a mesma coisa que foi feito em Color?! criaria uma variavel estatica representando BB, ITAU, BRADESCO que são objetos Banco ja configurados com suas taxas?! mas quanto a uma pessoa de fora do Brasil que usa sua classe, ele não quer nem saber quem são os bancos Brasileiros, seria justo ele ter que ficar olhando para aquele monte de banco criado que para ele não serve para nada?!
Vc criaria um builder para esses bancos do brasil?! se sim, como vc criaria ele?!

eu sei que analisando a parte de negócio isso não tem nada a ver, mas imagina que vc tivesse nessa exata situação.

valeu!

Utilize o pattern Strategy quando o comportamento variar.
No seu caso, utilize o pattern State, pois vc possui um estado (taxa de juros) variando de classe para classe.

Sim, mas eu quero saber como acessar esses estados. A maioria das vezes, vejo State/Strategy implementado criando-se uma nova classe que implementa o estado/estratégia, justamente pq na maioria das vezes uma mudança de estado ou de estratégia, resulta em uma mudança de comportamento tb. No exemplo do banco, poderia ter uma interface Banco com implementações (estados ou estratégias) para Bradesco, Itau, BB, e o usuário decidiria qual banco usar criando o proprio objeto do banco e se quizesse criar um banco especifico, implementaria o seu, mas acho que só faria sentido se cada banco tivesse um comportamento diferente.
Mas então vou falar mais especificamente da minha aplicação, que pode ser explique melhor o meu problema, eu tenho um modelo de simulação, para esse modelo é necessario informar um tipo de objeto que contém algumas configurações que vão interferir em como a simulação é realizada, essa configuração é composta por 4 atributos double por exemplo:

class Configuracao {
  private final double c1;
  private final double c2;
  private final double c3;
  private final double c4;
  public Configuracao (double c1, double c2, double c3, double c4) {
    this.c1 = c1;
    this.c2 = c2;
    this.c3 = c3;
    this.c4 = c4;
  }
  //gets
}

A assinatura do meu método de simulação seria então esse

Resultado simula(Configuracao conf, List<Data> dadosSimulacao);  

Porém existem 15 configurações pré definidas no mundo, que em 99% das simulações vai ser usada uma dessas configurações, e como o usuário dessa classe não vou ser eu (ela vai fazer parte tipo de uma api), quero dar a possibilidade do usuário do meu objeto de simulação escolher entre as 15 configurações ou então criar a sua própria. Mas acho que não é certo criar 15 subtipos de configuração só porque os parâmetros que passo no construtor são diferentes:

class Conf1 extends Configuracao {
  public Conf1() {
    super(1.1, 2.2, 3.3, 4.4);
  }
}

Mas tb não me agrada implementar da forma como Color foi implementado:

class Configuracao {
  private final double c1;
  private final double c2;
  private final double c3;
  private final double c4;
  public static final Configuracao CONF1 = new Configuracao(1.1, 2.2, 3.3, 4.4);

  public Configuracao (double c1, double c2, double c3, double c4) {
    this.c1 = c1;
    this.c2 = c2;
    this.c3 = c3;
    this.c4 = c4;
  }
  //gets
}

Acho que a solução para esse tipo de problema está mais relacionada a um pattern de contrução…

Então, o que eu queria é saber como vocês resolveriam isso, implementar da forma como Color esta (com public static dentro da propria classe Configuracao)?! criar 15 subtipos (um tipo para cada uma das Configurações)?! colocar as 15 configurações possiveis em um enum (como sugeri na abertura do post)?!
Eu não achei um pattern que me dissesse qual é a melhor solução para isso.

Valeu!

OK, seu problema é com a criação do objeto. Dê uma olhada nos padrões Factory e Abstract Factory. :wink:

eu conheço (pode não ser tão avançado) esses dois padrões, mas acho que não serve para esse caso…

Vamos la, vamos supor que eu queira um factory de figuras (classico):

Minhas figuras:

interface Figura
{
   void desenhar();
}

class Retangulo implements Figura
{

   public void desenhar()
   {
   }
}

class Circulo implements Figura
{

   public void desenhar()
   {
   }
}

meu factory:

abstract class Factory
{
   abstract Figura create();

   static Figura getFigura(int tipo)
   {
      switch (tipo)
      {
         case 1:
            return new CirculoFactory().create();
         case 2:
            return new RetanguloFactory().create();
      }
      throw new IllegalArgumentException();
   }
}

class CirculoFactory extends Factory
{
   public Figura create()
   {
      return new Circulo();
   }
}

class RetanguloFactory extends Factory
{
   public Figura create()
   {
      return new Retangulo();
   }
}

Tah, eh um factory bem ‘tosco’, mas blz, como eu uso isso?!

Factory.getFigura(1) 
ou 
Factory.getFigura(2)

ou no caso se meu parâmetro fosse string

Factory.getFigura("circulo") 
ou 
Factory.getFigura("rentagulo")

ou agora se eu tivesse um enum enumerando as figuras que o factory pode construir

enum Figura {
  CIRCULO, RETANGULO;
}

Factory.getFigura(Figura.CIRCULO) 
ou 
Factory.getFigura(Figura.RENTAGULO)

qual desses 3 vc acha melhor?! eu particularmente acho o terceiro com enum já que é checado. O que pensei foi, se o Factory vai criar todos objetos enumerados no enum, porque não deixar para o proprio enum criar a figura? no caso desse exemplo (da figura) eu NÃO faria com enum, pois existem inumeras formas de se criar um circulo (muda o comportamento do método desenhar), e não apenas uma forma, então acho que justifica ter um factory e o enum serviria apenas como parâmetro para o factory. Mas no exemplo das configurações do meu simulador acho que se aplica, não vai existir outra forma de se criar a configuração 1 (assim como não existe outra forma de criar a cor azul, vai ser sempre rgb 0,0,255), essa conf sempre sera com valores 1.1, 2.2, 3.3 e 4.4, como não vai haver outra forma de criar ela, porque não deixar para que o enum que representa ela crie?!

Agora as cores são padrões mundiais, então eu até “aceito” (embora ache feio) colocar as cores na própria classe Color como public static, mas minhas configurações não são padrões mundiais, aqui no Brasil usa-se 15 padrões com um valor, no Canada pode usar 10 padrões com outros valores, então não acho certo colocar como public static na classe Configuracao.

Tah, eu quero que vc me passe um codigo de como vc implementaria as cores padrões da classe Color sendo que “cor padrão” não é uma coisa unica em todo mundo, as cores padrões aqui no Brasil são o GREEN, YELLOW e MAGENTA, para o Canada são o CYAN, PINK e BLUE, e assim por diante, cada pais tem suas cores… e você quer que sua classe Color possa ser usada por qualquer um em todo mundo, mas claro, 90% das das pessoas que vão usar são brasileiras, então seria bom que vc tivesse uma pré implementação delas para esses usuários. O que você faz?! não vai criar todas cores padrões de todos paises do mundo na classe Color, seriam uma lambanssa que ninguem acharia nada, mas tb não vai colocar só as do Brasil, porque isso não interessa para o resto do mundo. Então para esse caso, eu pensei em criar um enum para representa-las:

enum CoresBrasil {
  GREEN() {
    Color get() {
      return new Color(0, 255, 0);
    }
  };
  
  public abstract Color get();
}

porque?!
não muda jamais, não existe outra forma de implementar o Color.GREEN no brasil, então não justificaria ter um Factory para ele, mas como ela é um padrão só aqui no brasil, não justificaria tb estar previamente criada como public static final Color GREEN na clase Color que é usada em todo mundo. Eu gostaria de sugestões de como fazer, ou melhor, ver como vocês fariam…
de qq forma, eu acho que ninguem mais vai responder, muita coisa escrita ja

flw

Com o pattern Abstract Factory vc cria fábricas de fábricas, ou seja, vc cria:

  • uma fábrica de cores para o Canadá ou
  • uma fábrica de cores para o Brasil ou
  • uma fábrica de taxas de juros com as configurações do cliente X ou
  • uma fábrica de taxas de juros com as configurações do cliente Y.

:wink: