I am working on refactoring some code I wrote awhile back, trying to make it more SOLID by implementing some design patterns. Specifically, I am trying to use the builder pattern to instantiate a GUI object.
Here is the code for the 'Product':
public class ContainerShell {
private JFrame mainView = new JFrame("Election Simulator");
private JTabbedPane tabbedPane = new JTabbedPane();
private PopulationController populationController;
private CandidateController candidateController;
private ElectionController electionController;
public JFrame getMainView() {
return mainView;
}
public JTabbedPane getTabbedPane() {
return tabbedPane;
}
public void addController(Controller uiController) throws RuntimeException {
switch (uiController.getType()) {
case POPULATION:
this.populationController = (PopulationController) uiController;
case CANDIDATE:
this.candidateController = (CandidateController) uiController;
case ELECTION:
this.electionController = (ElectionController) uiController;
default:
throw new RuntimeException("Unknown controller type");
}
}
public PopulationController getPopulationController() {
return populationController;
}
public CandidateController getCandidateController() {
return candidateController;
}
public ElectionController getElectionController() {
return electionController;
}
}
Here is the code for the 'Concrete Builder':
public class GuiBuilder implements Builder {
public static final Component contentPaddingX = Box.createRigidArea(new Dimension(10,0));
public static final Component contentPaddingY = Box.createRigidArea(new Dimension(0,10));
public static final Component borderPaddingX = Box.createRigidArea(new Dimension(20,0));
public static final Component borderPaddingY = Box.createRigidArea(new Dimension(0,20));
private ContainerShell voteSimGui = new ContainerShell();
public GuiBuilder() {
}
@Override
public void addPopulationController(PopulationController uiController) {
voteSimGui.addController(uiController);
}
@Override
public void addCandidateController(CandidateController uiController) {
voteSimGui.addController(uiController);
}
@Override
public void addElectionController(ElectionController uiController) {
voteSimGui.addController(uiController);
}
public ContainerShell build() {
voteSimGui.getTabbedPane().addTab("Population", voteSimGui.getPopulationController().getPopPane());
voteSimGui.getTabbedPane().addTab("Candidates", voteSimGui.getCandidateController().getCandPane());
voteSimGui.getTabbedPane().addTab("Election Results", voteSimGui.getElectionController().getElectPane());
voteSimGui.getMainView().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
voteSimGui.getMainView().getContentPane().add(voteSimGui.getTabbedPane());
voteSimGui.getMainView().pack();
voteSimGui.getMainView().setVisible(true);
return voteSimGui;
}
}
And the code for the 'Abstract Builder' interface:
public interface Builder {
void addPopulationController(PopulationController popController);
void addCandidateController(CandidateController candController);
void addElectionController(ElectionController electController);
}
Now here is the current working build method of the 'Director':
public void buildGUI() {
GuiBuilder guiBuilder = new GuiBuilder();
guiBuilder.addPopulationController(ControllerFactory.getPopulationInstance());
guiBuilder.addCandidateController(ControllerFactory.getCandidateInstance());
guiBuilder.addElectionController(ControllerFactory.getElectionInstance());
gui = guiBuilder.build();
}
Cool, so what's the problem, right? Well, it may be ultimately inconsequential, but this is my actual preferred implementation of that method:
gui = new GuiBuilder()
.addPopulationController(ControllerFactory.getPopulationInstance())
.addCandidateController(ControllerFactory.getCandidateInstance())
.addElectionController(ControllerFactory.getElectionInstance())
.build();
See how much cleaner that looks? Only problem is JetBrains is complaining about this for whatever reason...and I can't figure out why. The specific error the compiler gives is that it is unable to resolve the token 'addCandidateController' (but it accepts the addPopulationController). So taken together with the fact that the previous implementation worked tells me that this isn't necessarily an issue with this code's functionality so much as it simply doesn't like how I'm trying to chain the methods together. But then how come Java is allowed to do it?! (From another project):
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.kraken.com/0/private/Balance"))
.header("API-Key", auth.getPubKey())
.header("API-Sign", auth.sign("/0/private/Balance", "nonce=" + nonceValue))
.POST(HttpRequest.BodyPublishers.ofString("nonce=" + nonceValue))
.build();
Again, that's an example from a different project wherein I implement Java's HttpRequest.Builder; but that implementation works just fine. So what am I missing?