-
Once you get more than two or three flags, I would consider creating a class to store these settings to keep your design clean.
-
use the decorator pattern in order to dynamically adding behavior to your dialog
-
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.
-
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() );
-
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...
-
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);
-
As with many things, "it depends".
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()
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.
- If you can reasonably subclass (or compose), meaning that you usually only use a couple of combinations of all the booleans, then do that.
-
I have found that this kind of thing becomes MUCH more readable if I use enum
s 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.
-
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);
}
-
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.
-
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.