我一直在开发迷宫生成器/求解器程序。它工作得很好,但我在重构代码时遇到了一个问题。
基本上,我曾经直接从另一个类调用绘制解决迷宫过程的方法,而不是调用paintComponent方法(或者更确切地说是重新绘制方法(。很明显,这不是一个好的做法,也不是令人满意的表现,我正在努力克服这一点。
问题是,要绘制解决方案的子步骤,不同的求解算法需要不同类型和数量的参数。我可以将这些存储在一个类中,然后调用paintComponent方法,在该方法中,我调用使用上述参数绘制子步骤的方法。
不幸的是,这意味着我必须创建一堆其他类来扩展JPanel,这样我就可以存储必要的集合和变量,这样我就能绘制出一个特定的解决方案。
有没有更好的方法来解决这个问题,或者我应该放弃,按照我提到的方式去做?
所以我想做的是:
@Override
public void paintComponent(Graphics g){
super(g);
drawMaze(g);
switch(solverType) //Based on what solver is assigned to the maze it calls the proper method
{
case solver1:
solver1Drawer(g, additional arguments);
break;
case solver2:
solver2Drawer(g, different kind, and number of arguments);
break;
//Other cases, with other method calls
}
}
有很多方法可以构建这样的应用程序,它们可以接受不同的解算器和视图。我将尝试演示一个非常基本的、精简的,尽可能简单
为此,我们将使用一个解算器来计算某个形状的周长并绘制解决方案
首先,我们将定义一些接口,稍后应该会更清楚地使用这些接口:
interface Model{
boolean solve();
int solution();
boolean isSolved();
}
interface View{
void draw(Graphics g);
}
interface Solver {
Model getModel();
View getView();
}
使用这些接口,我们将定义M模型、V视图和C控制器,以支持正方形周长的计算
模型封装了信息(属性和状态(和逻辑:
class SquarePrimeterModel implements Model{
private final int edgeLength;
private int perimeter;
private boolean isSolved = false;
public SquarePrimeterModel(int edgeLength) {
this.edgeLength = edgeLength;
}
@Override
public boolean solve() {
perimeter = 4 * edgeLength;
isSolved = true;
return true;
}
@Override
public int solution() {
return perimeter;
}
@Override
public boolean isSolved() {
return isSolved;
}
//edgeLength is a unique property for this model
public int getEdgeLength() {
return edgeLength;
}
}
正如其名称所暗示的,视图生成视图的责任:
class SquarePrimeterView implements View{
private final static int xOffset = 50, yOffset = 50, GAP = 20;
private final SquarePrimeterModel model;
public SquarePrimeterView(SquarePrimeterModel model) {
this.model = model;
}
@Override
public void draw(Graphics g) {
if(model.isSolved()){
g.drawRect(xOffset, yOffset, model.getEdgeLength(), model.getEdgeLength());
String text = "Edge =" + model.getEdgeLength() + " Perimiter ="+ model.solution();
int yPosition = yOffset + model.getEdgeLength()+ GAP;
g.drawString(text, xOffset, yPosition);
}
}
}
控制器构建、配置和管理模型和视图:
class SquarePrimeterController implements Solver{
private final SquarePrimeterModel model;
private final View view;
public SquarePrimeterController(int edgeLength) {
model = new SquarePrimeterModel(edgeLength);
view = new SquarePrimeterView(model);
}
@Override
public Model getModel() {
return model;
}
@Override
public View getView() {
return view;
}
}
如果我们需要另一个解算器,例如,一个求解器来计算三角形的周长,我们只需编写与SquarePrimeter类非常相似的TriangelPrimeterController、TringelPrimeterModel和TriangelPrieterView
我们需要的最后一个pice代码是使用SquarePrimeterController
:的应用程序
public class SwingMVCSolveController {
public SwingMVCSolveController() {
Solver solver = new SquarePrimeterController(150);//todo: select solver by gui
solver.getModel().solve(); //todo start solve by gui
new MainView(solver.getView());
}
public static void main(String[] args) {
new SwingMVCSolveController();
}
}
class MainView extends JPanel {
private static final Dimension size = new Dimension(400, 400);
private final View solverView;
public MainView(View view) {
solverView = view;
createAndShowGui();
}
private void createAndShowGui() {
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add (this);
frame.pack();
frame.setVisible (true);
}
@Override
public Dimension getPreferredSize() {
return size;
}
@Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
solverView.draw(g);
}
}
显然,CCD_ 2可以被改变为CCD_ 3或CCD_ 4的任何其他实现
完整的可运行代码在这里可用