如何支持和绘制多种算法

How to support and paint multiple algorithms

我一直在研究迷宫 generator/solver 程序。它工作得很好,但我在重构代码时遇到了一个问题。

基本上,我过去常常调用直接从另一个 class 绘制解决迷宫过程的方法,而不是调用 paintComponent 方法(或者更确切地说是 repaint 方法)。显然这不是一个好的做法,在性能方面也不令人满意,我正在努力解决这个问题。

问题是,要绘制解决方案的子步骤,不同的求解器算法需要不同类型和数量的参数。 我可以将它们存储在 class 中,然后调用 paintComponent 方法,在该方法中我调用使用上述参数绘制子步骤的方法。

不幸的是,这意味着我必须创建一堆扩展 JPanel 的其他 classes,这样我就可以存储必要的集合和变量,这样我就可以绘制一个特定的解决方案。

有没有更好的方法来解决这个问题,还是我应该放弃并按照我提到的方式去做?

所以我想做的是:

@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;
    }
}

如果我们需要另一个求解器,例如计算三角形周长的求解器,我们只需编写 TriangelPrimeterController、TriangelPrimeterModel 和 TriangelPrimeterView,非常类似于 SquarePrimeter 类.

我们需要的最后一段代码是使用 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);
    }
}

显然 Solver solver = new SquarePrimeterController(150); 可以更改为 Solver solver = new TrianglePrimeterController(150);Solver 的任何其他实现。

完整的可运行代码可用here