patternjavaMinor
Looking for a better way to define and use constants
Viewed 0 times
waybetterlookingfordefineanduseconstants
Problem
In a custom Ant task, I have the following constants:
What the task should do is to run commands according to a given version control type. For example if I give it
The reason I separate them into three constants is that the outputs of them have to be handled in different ways.
The reason I use a map is that I don't want to use a lot of "if" or "switch-case" in my code. In the map there are keys like
private static final String _REVISION = ".revision";
private static final String _CODEBASE_INFO = ".codebase";
private static final String _DIFF = ".diff";
private static final String _TYPE_GIT = "git";
private static final String _TYPE_SVN = "svn";
private static final String[] _COMMAND_REV_GIT =
{"git", "rev-parse", "HEAD"};
private static final String[] _COMMAND_REV_SVN =
{"svn", "info"};
private static final String[][] _COMMAND_CODEBASEINFO_GIT = {
{"git", "branch", "-v"},
{"git", "remote", "-v"},
{"git", "log", "--max-count=1"},
{"git", "status"}};
private static final String[][] _COMMAND_CODEBASEINFO_SVN = {
_COMMAND_REV_SVN,
{"svn", "status"}};
private static final String[][] _COMMAND_DIFF_GIT = {
{"git", "diff", "HEAD"},
{"git", "diff", "HEAD", "--no-prefix"}};
private static final String[][] _COMMAND_DIFF_SVN = {
{"svn", "diff"}};
private static final Map _COMMANDS;
static {
Map map = new HashMap<>();
map.put(_TYPE_GIT + _REVISION, _COMMAND_REV_GIT);
map.put(_TYPE_SVN + _REVISION, _COMMAND_REV_SVN);
map.put(_TYPE_GIT + _DIFF, _COMMAND_DIFF_GIT);
map.put(_TYPE_SVN + _DIFF, _COMMAND_DIFF_SVN);
map.put(_TYPE_GIT + _CODEBASE_INFO, _COMMAND_CODEBASEINFO_GIT);
map.put(_TYPE_SVN + _CODEBASE_INFO, _COMMAND_CODEBASEINFO_SVN);
_COMMANDS = Collections.unmodifiableMap(map);
}What the task should do is to run commands according to a given version control type. For example if I give it
git then it will run commands in _COMMAND_REV_GIT, _COMMAND_CODEBASEINFO_GIT and _COMMAND_DIFF_GIT. The reason I separate them into three constants is that the outputs of them have to be handled in different ways.
The reason I use a map is that I don't want to use a lot of "if" or "switch-case" in my code. In the map there are keys like
git.revision, git.codebase, etc. If git is given when running this task, _COMMAND_REV_GIT will Solution
You should create an
and two implementations:
It would improve type safety a lot. (With a
Edit: I've changed the return types. Sample implementations are the following:
It fits well to
ScmCommands interface like this:public interface ScmCommands {
public String[] getRevisionCommand();
public List getDiffCommand();
public List getCodebaseInfoCommand();
}and two implementations:
SvnCommands, GitCommands.It would improve type safety a lot. (With a
Map you usually have to cast the values which is error-prone). Furthermore, it eliminates the magic constants. It's easy to call Map.get() with a mistyped key. With the interface the compiler warns you if the method name is wrong.Edit: I've changed the return types. Sample implementations are the following:
public class GitCommands implements ScmCommands {
private static final String GIT_COMMAND = "git";
public GitCommands() {
}
@Override
public String[] getRevisionCommand() {
return new String[] { GIT_COMMAND, "rev-parse", "HEAD" };
}
@Override
public List getDiffCommand() {
final List result = new ArrayList();
result.add(new String[] { GIT_COMMAND, "diff", "HEAD" });
result.add(new String[] { GIT_COMMAND, "diff", "HEAD", "--no-prefix" });
return result;
}
@Override
public List getCodebaseInfoCommand() {
final List result = new ArrayList();
result.add(new String[] { GIT_COMMAND, "branch", "-v" });
result.add(new String[] { GIT_COMMAND, "remote", "-v" });
result.add(new String[] { GIT_COMMAND, "log", "--max-count=1" });
result.add(new String[] { GIT_COMMAND, "status" });
return result;
}
}public class SvnCommands implements ScmCommands {
private static final String SVN_COMMAND = "svn";
public SvnCommands() {
}
@Override
public String[] getRevisionCommand() {
return new String[] { SVN_COMMAND, "info" };
}
@Override
public List getDiffCommand() {
final List result = new ArrayList();
result.add(new String[] {SVN_COMMAND, "diff"});
return result;
}
@Override
public List getCodebaseInfoCommand() {
final List result = new ArrayList();
result.add(new String[] { SVN_COMMAND, "status" });
return result;
}
}It fits well to
ProcessBuilder but I'd consider extracting out all SCM related methods to an interface (for example Scm), and move the code to SCM-specific classes which implement the Scm interface, like GitScm, SubversionScm etc. Calling command line executables doesn't smell good, maybe it would be better to use native Subversion and Git Java libraries.Code Snippets
public interface ScmCommands {
public String[] getRevisionCommand();
public List<String[]> getDiffCommand();
public List<String[]> getCodebaseInfoCommand();
}public class GitCommands implements ScmCommands {
private static final String GIT_COMMAND = "git";
public GitCommands() {
}
@Override
public String[] getRevisionCommand() {
return new String[] { GIT_COMMAND, "rev-parse", "HEAD" };
}
@Override
public List<String[]> getDiffCommand() {
final List<String[]> result = new ArrayList<String[]>();
result.add(new String[] { GIT_COMMAND, "diff", "HEAD" });
result.add(new String[] { GIT_COMMAND, "diff", "HEAD", "--no-prefix" });
return result;
}
@Override
public List<String[]> getCodebaseInfoCommand() {
final List<String[]> result = new ArrayList<String[]>();
result.add(new String[] { GIT_COMMAND, "branch", "-v" });
result.add(new String[] { GIT_COMMAND, "remote", "-v" });
result.add(new String[] { GIT_COMMAND, "log", "--max-count=1" });
result.add(new String[] { GIT_COMMAND, "status" });
return result;
}
}public class SvnCommands implements ScmCommands {
private static final String SVN_COMMAND = "svn";
public SvnCommands() {
}
@Override
public String[] getRevisionCommand() {
return new String[] { SVN_COMMAND, "info" };
}
@Override
public List<String[]> getDiffCommand() {
final List<String[]> result = new ArrayList<String[]>();
result.add(new String[] {SVN_COMMAND, "diff"});
return result;
}
@Override
public List<String[]> getCodebaseInfoCommand() {
final List<String[]> result = new ArrayList<String[]>();
result.add(new String[] { SVN_COMMAND, "status" });
return result;
}
}Context
StackExchange Code Review Q#7949, answer score: 7
Revisions (0)
No revisions yet.