views:

443

answers:

11

I have a dialog that displays various things depending on state of the application, security for the current user etc. I am currently passing in several boolean flags and then enabling and/or hiding UI components depending on these flags.Eg:

new MyDialog(showOptionsTable, allowFooInput, allowBarInput, isSuperUser)

Initially this started out as a couple of flags and that was fine. But now with changing requirements, it has evolved into an input of five boolean flags.

What is the best practices way of handling behavior like this? Is this something that I should subclass depending on how the dialog should look?

+8  A: 

Once you get more than two or three flags, I would consider creating a class to store these settings to keep your design clean.

Chris Ballance
Do you mean a java bean with properties?
Kapsh
Yes, A Java Bean would work nicely for this
Chris Ballance
+2  A: 

use the decorator pattern in order to dynamically adding behavior to your dialog

dfa
+1 for giving a relevant OO pattern.
Chris Ballance
can you post sample pseudo for the decorator pattern?
OscarRyz
http://en.wikipedia.org/wiki/Decorator_pattern contains the classic example using a Window and WindowDecorator
dfa
Thanks for the link. Not I get the concept of the Decorater pattern, but I don't understand how to apply it here. :-/
OscarRyz
you can write a Decorator for each boolean: i.e. OptionTableDecorator, SuperUserDecorator, etc. This design allow you to add new behaviour to your original dialog dynamically, your booleans is translated to a chain of decorator, that is much more simpler to maintain. Hope it helps :)
dfa
A: 

Set it up so MyDialog(false, false, .....) is the expected default behaviour. (ie: The most common case should take all false. You may need to reverse the semantics of the flags.)

Now, define constants:

OPTION1 = 1
OPTION2 = 2
OPTION3 = 4
OPTION4 = 8
...

Change the method to take an int options parameter

public void MyDialog(int options) ...

Now call it:

MyDialog(OPTION1 | OPTION3)  // enable Opt1, opt2)

inside the method:

if (options & OPTION1) // use Option 1 config.

etc.

chris
That being said, refactoring and subclassing might very well be a better option.
chris
I'd prefer an enum instead of raw ints.
Michael Myers
Yeah, but keep it simple stupid -- That's just a prettification.
chris
Prettification, and less bug-prone.
Michael Myers
yes. This is more of an old-school C way of doing it.
Zack
This might be the canonical way in C, but it's definitely a code smell in Java. At least *I* would criticize it in a code review. I don't want my API designers to require our API users to do bit manipulation for simply selecting a few options.
Joachim Sauer
A: 

If the GUI depends on the state of the app ( where one state leads to another ) You can take a look at the State pattern. Where each new state will be handled by a different object and you can code whether the flags should go or no.

ie.

abstract class State { 
      public abstract boolean [] getFlags();
      public abstract State next();
 }
 class InitialState extends State  { 
      public boolean [] getFlags() {
          return new boolean [] { true, true, false, false, false };
      }
      public State next() { return new MediumState(); }
 }     
 class MediumState extends State { 
     public boolean [] getFlags() { 
         return new boolean[] { false, false, true, true, false };
     }
     public State next() { return new FinalState(); }
 }
 class Final extends State { 
     public boolean [] getFlags() { 
         return new boolean[]{false, false, false, false, true };
     }
     public State next() { return null;}
  }

And the show your dialog using this states

new MyDialog(showOptionsTable, new InitialState() );

....

When the state of the application changes, you change the State object.

public void actionPerfomed( ActionEvent e ) { 
    this.state = state.next();
    repaint();
 }

To paint the sections of your dialog you query the state:

  if( state.getFlags()[SECURITY] ) { 
      /// show security stuff
  } if ( state.getFlags()[VIEW_ONLY] ) { 
      // enable/disable stuff 
  } ....

You can go a step further ant let the State define what is presented.

abstract class State { 
      public abstract JComponent getComponent();
      public abstract State next();
 }

So each state shows a different section:

 Dialog.this.setContentPane( state.getComponent() );
OscarRyz
This would result in an exponential number of states being created when more check boxes are added. State pattern would probably be better if this portion of the code were unlikely to increase in the number of states. However, this doesn't seem to be the case.
Zack
+2  A: 

Create a class to hold your configuration options:

public class LayoutConfig
{
    public boolean showOptionsTable = true;
    public boolean allowFooInput = true;
    public boolean allowBarInput = true;
    public boolean isSuperUser = true;
}

...

LayoutConfig config = new LayoutConfig();
config.showOptionsTable = false;

new MyDialog(config);

This approach makes it easy to add new options without changes your interface. It will also enable you to add non-boolean options such as dates, numbers, colors, enums...

Ben Noland
+2  A: 

To build on Ben Noland answer, you could define some options as enum, then have a varargs constructor:

class MyDialog {
   enum DialogOptions {
      SHOW_OPTIONS_TABLE, ALLOW_FOO_INPUT, ALLOW_BAR_INPUT, IS_SUPER_USER
   }
   public MyDialog(DialogOptions ...options) { ... }
}

...
new MyDialog(DialogOptions.ALLOW_FOO_INPUT, DialogOptions.IS_SUPER_USER);
penpen
I suppose I should look into varargs considering that these options might change in the near future.
Kapsh
+8  A: 

As with many things, "it depends".

  1. Ben Noland suggested a class to hold configuration options. This is doable, but favor immutability, and optionally use the builder pattern. Because booleans are built-in types, writing a small builder will really help people understand the code. If you compare this to MyDialog(true, true, ...) you know what I mean:

    Options.allowThis().allowThat().build()

  2. Chris suggested bit fields, but as some of the commenters point out, bit fields are evil because of many reasons outlined in Josh Bloch's Effective Java. Basically they are hard to debug and error prone (you can pass in any int and it will still compile). So if you go this route, use real enums and EnumSet.

  3. If you can reasonably subclass (or compose), meaning that you usually only use a couple of combinations of all the booleans, then do that.
RobbieV
+1 Good summary!
Kapsh
Don't understand why this was downvoted; I'd probably agree that Enum and an EnumSet are the way to go here.
Rob
A: 

I have found that this kind of thing becomes MUCH more readable if I use enums for the boolean choices.

public enum ShowOptionsTable { YES, NO }
public enum AllowFooInput { YES, NO }
public enum AllowBarInput { YES, NO }
public enum IsSuperUser { YES, NO }

new MyDialog(ShowOptionsTable.YES, AllowFooInput.NO, AllowBarInput.YES,
             IsSuperUser.NO);

With enums like this, usage of code with a lot of boolean parameters becomes easy to understand. Also, since you are using objects rather than booleans as parameters, you have use other patterns to easily refactor things later if you want, to use a decorator or a facade or some other pattern.

Eddie
A: 

I prefer flagged enums to a settings class if the parameters are all going to be boolean. If you can't guarantee that in the future though it would be better safe than sorry though. Here's another implementation for flags:

[Flags]
public enum LayoutParams
{  
    OptionsTable = 1,  
    FooInput = 2,  
    BarInput = 4,  
    SuperUser = 8,
}

public MyDialog(LayoutParams layoutParams)
{
    if (layoutParams & LayoutParams.OptionsTable)
    { /* ... Do Stuff ... */ }
}

public static MyDialog CreateBasic()
{
    return new MyDialog(LayoutParams.OptionsTable | LayoutParams.BarInput);
}
Jeremy
In Java, it would be `return new MyDialog(EnumSet.of(LayoutParams.OptionsTable, LayoutParams.BarInput));`
Michael Myers
You're right. I think in C#, apparently.
Jeremy
A: 

Depending on just how different your display is going to be, you might consider subclassing your display class (i.e. MyDialogSuperUser or somesuch). You need to consider just how orthogonal the inputs to your dialog class are and how to express that orthogonality.

McWafflestix
A: 

I have a favorite way to handle this, but it's not valid for all use cases. If the booleans are not entirely independent (say there are some invalid combinations of booleans, or combinations of booleans are reached through identifiably scenarios.) I create an enum for the state and then define a constructor that holds onto the flags:

public enum status {
    PENDING(false,false),
    DRAFT(true,false),
    POSTED(false,true),
    ;
    public boolean isSent;
    public boolean isReceived;
    status(boolean isSent, boolean isReceived) {
        this.isSent = isSent;
        this.isReceived = isReceived;
    }
}

The advantage to a piece of code like this is that you can construct your enum constants relatively tersely, but still allow code to only care about one particular aspect of state. For example:

//I want to know specifically what the state is
if (article.state == status.PENDING)
// Do something

//I really only care about whether or not it's been sent
if (article.state.isSent)
// Do something

//I want to do something specific for all possible states
switch(article.state)
// A string of case statements

Another plus is that illegal states are never reached if you define your enum well:

if (article.state.isReceived && !article.state.isSent) {
// This block can never execute ever.
}

Granted, it's not all the time that there's a logical relationship among booleans, but I do recommend mapping them out. If a subset of booleans have logical relationships, it might be worth breaking those off into an enum.

David Berger