简体   繁体   English

在侦听器的handle方法中是否有最佳方法来调用控制器类的方法?

[英]Is there a best practice way for calling methods of controller class in handle method of a listener?

I am developing a small game and was wondering about a best practice for handle methods in (anonymous) listeners. 我正在开发一个小型游戏,想知道有关(匿名)侦听器中的处理方法的最佳实践。 Although I am developing with libGDX in particular, my question is about java programming standards in general. 尽管我特别使用libGDX进行开发,但是我的问题是关于Java编程标准的。

Suppose I have a controller controlling screen classes containing a stage each. 假设我有一个控制器来控制每个包含一个舞台的屏幕类。 These stages build up the gui including buttons and so on. 这些阶段建立了gui,包括按钮等。 I'm adding click listeners as anonymous classes for the buttons in the stage. 我将单击侦听器添加为阶段中按钮的匿名类。 As I want to call methods of the screen or even the controller class in the handle method I am passing down a reference to them from controller to screen to stage to listener. 因为我想在handle方法中调用屏幕的方法甚至是控制器类,所以我将对它们的引用从控制器传递到屏幕,再传递到侦听器。 This passing down the reference appears to me as not being good practice. 在我看来,忽略参考文献并不是一种好习惯。

Alternatively I could get the buttons in screen class and add the listeners there. 另外,我可以在屏幕课程中获取按钮,然后在其中添加侦听器。 I would need to add get-methods for each button then though. 但是,我需要为每个按钮添加get-method。

Could you think about any other cleaner way of implementing this? 您能考虑采用其他更清洁的方式来实现这一点吗?

I think towards the end of your question you are on the right path, but let's use some general (not even Java-specific) programming principles to understand why that's the right approach. 我认为在您问题的结尾,您走的路是正确的,但是让我们使用一些通用的(甚至不是Java特定的)编程原理来理解为什么这是正确的方法。 Here are our principles: 这是我们的原则:

  1. Separation of Concerns (SoC): Make sure your code does one thing and that one thing very well. 关注点分离(SoC):请确保您的代码可以完成一件事,并且可以很好地完成一件事。
  2. Don't Repeat Yourself (DRY): Code everything once; 不要重复自己(DRY):对所有内容进行一次编码。 minimize boilerplate code. 最小化样板代码。
  3. Keep it Simple (KISS): It'll be easier to read, easier to maintain, and easier to test. 保持简单(KISS):它将更易于阅读,易于维护和测试。

When I create a game screen in libGDX, I typically use the following structure: 在libGDX中创建游戏屏幕时,通常使用以下结构:

Screen
|- Stage
|- ControllerReference
\- ModelReference

The screen has a private stage which only it uses to create the layout for that particular screen. 该屏幕具有一个专用舞台,只有该舞台才可以用来创建该特定屏幕的布局。 I then inject a controller (used primarily for changing screens) and a model (dynamic game data) into the screen as demonstrated in the sample code below: 然后,我将一个控制器(主要用于更改屏幕)和一个模型(动态游戏数据)注入屏幕,如下面的示例代码所示:

StageScreen.java StageScreen.java

abstract class StageScreen implements Screen {
    protected Stage stage;
    protected Game controller;

    public StageScreen(Game controller) {
        this.controller = controller;
    }

    @Override
    public void render(float v) {
        stage.act(v);
        stage.draw();
    }

    @Override
    public void dispose() {
        stage.dispose();
    }
    // Snipped other methods like "hide" and "resize" which aren't relevant
}

MenuScreen.java MenuScreen.java

class MenuScreen extends StageScreen {
    private Array<Demo> demos;

    public MenuScreen(Game controller, Array<Demo> demos) {
        super(controller);
        this.demos = demos;
    }

    @Override
    public void show() {
        stage = new Stage(new ScreenViewport());
        Gdx.input.setInputProcessor(stage);

        VisTable table = new VisTable();
        table.setFillParent(true);

        for(final Demo demo : demos) {
            table.add(new VisTextButton(demo.getName(), new ChangeListener() {
                @Override
                public void changed(ChangeEvent changeEvent, Actor actor) {
                    controller.setScreen(demo);
                }
            }));
            table.row();
        }

        stage.addActor(table);
    }
}

So let's throw some rocks at the example: 因此,让我们在该示例中放一些石头:

  1. Does it separate concerns? 它会分离关注点吗? Yes . 是的 All the screen does is render a button for each demo, and tell the controller the user's intent. 屏幕所做的只是为每个演示呈现一个按钮,并告诉控制器用户的意图。 All it knows is that Demos have names and that they count as screens. 它所知道的就是演示有名称,并且它们被视为屏幕。 We could make our controller more abstract by passing it an event (ie "UserSelectsDemoX") instead of the screen we want to transition to, but I would argue that this would violate the KISS principle. 通过向它传递一个事件(即“ UserSelectsDemoX”)而不是我们想要转换的屏幕,可以使我们的控制器更加抽象,但是我认为这将违反KISS原则。
  2. Does it make us repeat ourselves? 这会让我们重复一遍吗? No. The code that is common to all screens (management of the Stage, keeping a reference to the folder) is in our abstract class, and our child class only contains code needed to make that Screen do something other screens don't. 。所有屏幕通用的代码(舞台的管理,对文件夹的引用)在我们的抽象类中,而我们的子类仅包含使Screen执行其他屏幕所不具备的操作所需的代码。
  3. Is it simple? 简单吗? Yes. 是。 Notice that if you are familiar with basic libGDX classes ( Game , Stage , Screen ), you don't need any comments to understand what this code snippet does. 请注意,如果您熟悉基本的libGDX类( GameStageScreen ),则无需任何注释即可了解此代码片段的功能。 We could make things more general (ie make a controller interface and a model interface that only reveal what our screen needs), but adding additional abstraction would just make the code harder to understand. 我们可以使事情变得更通用(即,使控制器接口和模型接口仅显示我们屏幕的需求),但是添加其他抽象只会使代码更难于理解。

Hopefully this helps answer your question around the best way to link your listeners to your controller, as well as give you a way of thinking that you can apply to other parts of your codebase. 希望这有助于围绕将侦听器链接到控制器的最佳方法回答您的问题,并为您提供一种思维方式,使您可以将其应用于代码库的其他部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM