tags:

views:

95

answers:

3

Hello all,

In my project, I have such class :

class Statut {
    String satDomain;
    String staCode;
}

But working with Strings is not what I want. It is too permisive and using constants is not enough.

I wanted to use enums but find a problem :

class Statut {
    Domain satDomain;
    StatutCode staCode;
}
enum Domain { }
enum StatutCode { }

This solution is far better, but you can set a StatutCode that is not in the selected Domain.

Did you find a solution in your project to such problem ?

Thank for your help

Fluminis

+2  A: 

I suggest making your fields private and final and adding a constructor the verifies that the constructed object is well-formed.

Tom Hawtin - tackline
Why not but it is not possible in the context of the project.In fact, I have a service that call the DB to get the full Statut objects defined like that :List<Statut> findStatus(String domain, List<String> staCodes);or like that in the second exempleList<Statut> findStatus(Domain domain, List<StatutCode> staCodes);And I call the method this way :findStatus(MyConst.DOMAIN_1, Arrays.asList(MyConst.STA_CODE_1, MyConst.STA_CODE_2))I want the constants itself are linked to the domain...
flumins
@flumins There appear to be architectural issues with the way you are handling your database.
Tom Hawtin - tackline
You're right, the model is a little messy but I think such case can appears in other project as well, isn't it ?
flumins
@flumins I don't mean the "domain model", but the difficult to change decisions made about interfacing with the database.
Tom Hawtin - tackline
+2  A: 

I don't usually find that a problem. I tend to use a unmodifiable validation Map<Domain,StatutCode>()` if run-time validation is sufficient, or the contents is pulled from a database.

You could add such a validator on Statut. Make the only setter like setDomainAndStatutCode(Domain domain, StatutCode statutCode) and check whether the input is valid.

Otherwise I'd use an enum DomainAndStatutCode. Lot's of work and maintenance of course, so really not a nice solution. Might be good if the dataset is limited and correctness is a must.

extraneon
+1. The only suggestion, since `Domain` will be an enum, use `EnumMap` ( not `HashMap`) for validation map. It's much more efficient.
Alexander Pogrebnyak
+2  A: 

Actually slight improvement on extraneon's answer.

Define StatutCode enum first, and then assign EnumSet< StatutCode > to each Domain enum value. Then the validation is pretty simple in Statut constructor

enum StatutCode
{
  ONE,
  TWO,
  THREE,
  FOUR
};

enum Domain
{
  DOMAIN_1( EnumSet.of( StatutCode.ONE, StatutCode.TWO ) ),
  ...
  DOMAIN_N( EnumSet.of( StatutCode.TWO, StatutCode.THREE ) );

  private final EnumSet< StatutCode> validStatCodes;

  Domain( EnumSet< StatutCode > validStatCodes )
  {
    this.validStatCodes = validStatCodes;
  }

  public boolean isValidCode ( final StatutCode code )
  {
    return validStatCodes.contains( code );
  }
}

class Statut {
    final Domain staDomain;
    final StatutCode staCode;

    Statut(
      final Domain staDomain,
      final StatutCode staCode
    )
    {
      if ( ! staDomain.isValidCode( staCode ) )
      {
        throw new IllegalArgumentException(
            "Invalid code " + staCode + " for domain " + staDomain
          );
      }

      this.staDomain = staDomain;
      this.staCode = staCode;
    }

}
Alexander Pogrebnyak
Yeah ! Nice solution !I will try this. Thanks
flumins