【问题标题】:Moving a circle on a map using Observer pattern使用观察者模式在地图上移动一个圆圈
【发布时间】:2018-05-09 06:00:29
【问题描述】:

我的 java 程序有一个(可能是一个简单的)问题。我正在尝试创建一个可以从一个地方移动到另一个地方的圆圈。地图是一个简单的对话游戏的一部分,上面写着“去这里”,地图应该对此做出反应。它必须使用观察者设计模式。

到目前为止,我已经在游戏中实现了地图,但我无法理解如何在使用 Observer 的同时使圆圈发挥应有的作用。感谢您的帮助

package GUI;

import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import logika.Game;
import logika.IGame;
import main.Main;
import utils.Observer;


public class Mapa extends AnchorPane implements Observer{

    private IGame game;
    private Circle dot;
    //private double posTop = 0.0;
    //private double posLeft = 0.0;

    public Mapa(IGame game){
            this.game = game;
            game.getGamePlan().registerObserver(this);
            init();
    }

    private void init(){

        ImageView obrazekImageView = new ImageView(new Image(Main.class.getResourceAsStream("/zdroje/mapa.gif"),255,255,false,true));

        tecka = new Circle(10, Paint.valueOf("red"));

       //this.setTopAnchor(tecka, 15.0);
       //this.setLeftAnchor(tecka, 20.0);

        this.getChildren().addAll(obrazekImageView, dot);
        update();
    }

    public void newGame(IGame newGame){
        game.getGamePlan().removeObserver(this);
        game= newGame;
        game.getGamePlan().registerObserver(this);
        update();

    }

    @Override
    public void update(){
        this.setTopAnchor(this, game.getGamePlan().getCurrentPlace().getPosTop());
        this.setLeftAnchor(this, game.getGamePlan().getCurrentPlace().getPosLeft());
    }
}

【问题讨论】:

  • 该模式背后的想法是所有观察者(或监听者)都注册一个事件。如果事件发生,它将通知所有观察者(调用他们的方法)。 观察者可以对事件做出反应。 (对比来自维基百科的UML diagram
  • 您能否更具体地说明您尝试实现的总体目标?我不明白你想如何使用该模式,因为我不明白你想要实现的目标。
  • 当然。我需要点(简单的圆圈)从这里开始 i.imgur.com/lrlJqK4.jpg ,然后我需要它向左/向右/(从那里可以去的任何地方)我在对话游戏中命令。我需要它在命令后做出反应,以便它知道去哪里。我希望我很清楚,英语不是我的第一语言:-)
  • 您可以编辑您的答案并包含您刚才所说的内容。我认为您应该为每个图像创建一个具体的Observer。对于事件,您可以选择“输入命令”,然后作为观察者,如果不是您的图片则拒绝,如果是您的图片。所以这次活动将是一种public void commandEntered(String command, Circle circle)
  • 是否有可能在地图旁边有一个组合框窗口之类的东西,您可以在其中选择您想去的地方,并且点会随着您选择的任何东西移动?因此,您可以根据您在组合框中选择的内容将圆的位置编码为 xy。尽管那时似乎很难编码

标签: java design-patterns geometry observer-pattern observers


【解决方案1】:

您应该像在维基百科的这个 UML 图中看到的那样实现模式:

也就是说,您将拥有一个类似CommandObserver接口,以及一个类似notify 的方法,每次事件发生时都会在每个观察者上调用该方法。该事件包含确切的 命令 以及移动圆圈所需的所有内容。我假设您可以通过仅引用圆圈来移动它。总而言之,它可能看起来像

public interface CommandObserver {
    void notify(String command, Circle circle);
}

接下来,事件的invoker(我们称之为CommandReceiver)必须有一些register方法,所有的观察者都可以注册。如果事件发生,它必须有某种notifyObservers 来调用:

public class CommandReceiver {
    // The reference to the circle
    private Circle circle = ...

    private Set<CommandObserver> observers = new HashSet<>();

    public void registerObserver(CommandObserver observer) {
        observers.add(observer);
    }

    public void unregisterObserver(CommandObserver observer) {
        observers.remove(observer);
    }

    private void notifyObserver(String command, Circle circle) {
        for (CommandObserver observer : observers) {
            observer.notify(command, circle);
        }
    }

    // If a command was entered
    public void commandEntered(String command) {
        notifyObserver(command, circle);
    }
}

最后,您将为所有可能的命令实现观察者,例如:

public PositionMoveObserver implements CommandObserver {
    private int x;
    private int y;
    private String command;

    public PositionMoveObserver(int x, int y, String command) {
        this.x = x;
        this.y = y;
        this.command = command;
    }

    @Override
    public void notify(String command, Circle circle) {
        // Not interested in, reject
        if (!this.command.equals(command)) {
            return;
        }

        // Move the circle to our destination
        circle.moveTo(x, y);
    }
}

然后为每个位置创建并注册它:

private void createObservers(CommandReceiver invoker) {
    invoker.registerObserver(new PositionMoveObserver(0, 5, "bottomLeft"));
    invoker.registerObserver(new PositionMoveObserver(100, 5, "bottomRight"));
    invoker.registerObserver(new PositionMoveObserver(0, 50, "middleLeft"));
    ...
}

注意,对于一个特定的命令,只有一个观察者应该听它,否则多个实例会移动圆圈,结果将取决于调用者HashSet的迭代顺序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 2016-02-20
    • 2023-04-10
    • 1970-01-01
    相关资源
    最近更新 更多