设计和目标责任问题(A question of design and object responsi

2019-06-28 08:03发布

我有一个设计和对象结构相关的问题。 这是问题的声明:

  1. 我有一个是假设遍历自身地面机器人对象。 这将提供移动指令,它必须相应地解析。 例如样本输入将是:一。 RotateRight |移动| RotateLeft |搬家|搬家|移动

凡此举是在网格单元运动。

我没有在java中一个非常基本的设计。 (下完成粘贴代码)

package com.roverboy.entity;

import com.roverboy.states.RotateLeftState;
import com.roverboy.states.RotateRightState;
import com.roverboy.states.State;

public class Rover {

    private Coordinate roverCoordinate;
    private State roverState;

    private State rotateRight;
    private State rotateLeft;
    private State move;

    public Rover() {
        this(0, 0, Compass.NORTH);
    }

    public Rover(int xCoordinate, int yCoordinate, String direction) {
        roverCoordinate = new Coordinate(xCoordinate, yCoordinate, direction);
        rotateRight = new RotateRightState(this);
        rotateLeft = new RotateLeftState(this);
        move = new MoveState(this);
    }

    public State getRoverState() {
        return roverState;
    }

    public void setRoverState(State roverState) {
        this.roverState = roverState;
    }

    public Coordinate currentCoordinates() {
        return roverCoordinate;
    }

    public void rotateRight() {
        roverState = rotateRight;
        roverState.action();
    }

    public void rotateLeft() {
        roverState = rotateLeft;
        roverState.action();
    }

    public void move() {
        roverState = move;
        roverState.action();
    }
}


package com.roverboy.states;

public interface State {

    public void action();
}

package com.roverboy.entity;

import com.roverboy.states.State;

public class MoveState implements State {

    private Rover rover;

    public MoveState(Rover rover) {
        this.rover = rover;
    }

    public void action() {
        rover.currentCoordinates().setXCoordinate(
                (Compass.EAST).equalsIgnoreCase(rover.currentCoordinates()
                        .getFacingDirection()) ? rover.currentCoordinates()
                        .getXCoordinate() + 1 : rover.currentCoordinates()
                        .getXCoordinate());

        rover.currentCoordinates().setXCoordinate(
                (Compass.WEST).equalsIgnoreCase(rover.currentCoordinates()
                        .getFacingDirection()) ? rover.currentCoordinates()
                                .getXCoordinate() - 1 : rover.currentCoordinates()
                                .getXCoordinate());

        rover.currentCoordinates().setYCoordinate(
                (Compass.NORTH).equalsIgnoreCase(rover.currentCoordinates()
                        .getFacingDirection()) ? rover.currentCoordinates()
                                .getYCoordinate() + 1 : rover.currentCoordinates()
                                .getYCoordinate());

        rover.currentCoordinates().setYCoordinate(
                (Compass.SOUTH).equalsIgnoreCase(rover.currentCoordinates()
                        .getFacingDirection()) ? rover.currentCoordinates()
                                .getYCoordinate() - 1 : rover.currentCoordinates()
                                .getYCoordinate());
    }
}


package com.roverboy.states;

import com.roverboy.entity.Rover;

public class RotateRightState implements State {

    private Rover rover;

    public RotateRightState(Rover rover) {
        this.rover = rover;
    }

    public void action() {
        rover.currentCoordinates().directionOnRight();
    }

}

package com.roverboy.states;

import com.roverboy.entity.Rover;

public class RotateLeftState implements State {

    private Rover rover;

    public RotateLeftState(Rover rover)
    {
        this.rover = rover;
    }

    public void action() {
        rover.currentCoordinates().directionOnLeft();
    }

}


package com.roverboy.entity;

public class Coordinate {

    private int xCoordinate;
    private int yCoordinate;
    private Direction direction;
    {
        Direction north = new Direction(Compass.NORTH);
        Direction south = new Direction(Compass.SOUTH);
        Direction east = new Direction(Compass.EAST);
        Direction west = new Direction(Compass.WEST);
        north.directionOnRight = east;
        north.directionOnLeft = west;
        east.directionOnRight = north;
        east.directionOnLeft = south;       
        south.directionOnRight = west;
        south.directionOnLeft = east;
        west.directionOnRight = south;
        west.directionOnLeft = north;
        direction = north;
    }

    public Coordinate(int xCoordinate, int yCoordinate, String direction) {
        this.xCoordinate = xCoordinate;
        this.yCoordinate = yCoordinate;
        this.direction.face(direction);
    }

    public int getXCoordinate() {
        return xCoordinate;
    }
    public void setXCoordinate(int coordinate) {
        xCoordinate = coordinate;
    }
    public int getYCoordinate() {
        return yCoordinate;
    }
    public void setYCoordinate(int coordinate) {
        yCoordinate = coordinate;
    }

    public void directionOnRight()
    {
        direction.directionOnRight();
    }

    public void directionOnLeft()
    {
        direction.directionOnLeft();
    }

    public String getFacingDirection()
    {
        return direction.directionValue;
    }
}

class Direction
{
    String directionValue;
    Direction directionOnRight;
    Direction directionOnLeft;

    Direction(String directionValue)
    {
        this.directionValue = directionValue;
    }

    void face(String directionValue)
    {
        for(int i=0;i<4;i++)
        {
            if(this.directionValue.equalsIgnoreCase(directionValue))
                break;
            else
                directionOnRight();
        }
    }

    void directionOnRight()
    {
        directionValue = directionOnRight.directionValue;
        directionOnRight = directionOnRight.directionOnRight;
        directionOnLeft = directionOnRight.directionOnLeft;             
    }

    void directionOnLeft()
    {
        directionValue = directionOnLeft.directionValue;
        directionOnRight = directionOnLeft.directionOnRight;
        directionOnLeft = directionOnLeft.directionOnLeft;      
    }
}

现在我的疑问是这个最后一堂课“方向”和“协调”。 坐标表示为流动站这有助于它保持其方向坐标的对象。 目前跟踪的方向,我使用方向对象的双向链表,就像指南针一样,其相当多的工作。 向左或向右旋转。

下面是我有问题。 1.我已经使用状态模式和示出了用于跟踪方向设计。 有没有更好的方法来简化甚至这个? 雷姆。 我需要保持正确的坐标; 例如,如果你对+ Y轴移动,我的坐标应该在别的+在零下。 同为X轴。

  1. 目前改变流动站面对的责任是间接交给坐标和方向类。 这真的是正确的吗? 是不是罗孚负责维护的方向吗? 我真的就在我的设计委托的责任下,协调和指导类; 只是因为它更容易有操纵呢?

  2. 任何简单的设计改进和建议代码将是最欢迎的。 随意批评。

感谢您的耐心和反馈; 提前。

Answer 1:

你问如何简化。 如果我可以建议一些大胆的,为什么不使用不透明INT的方向有一个静态类来处理呢? 所谓“不透明INT”我的意思是,你的代码永远不会直接使用它,而只是作为参数的方向类。

下面是一些局部的Java风格的伪代码,以显示我的意思。

// 0 = east, 1 = north, 2 = west, ...
public class Direction {
  static int [] moveX = [ 1, 0, -1, 0];
  static final int NORTH = 1;
  // coordinates after moving one step in the given direction
  static Pair move(int direction, Pair old) {
     return new Pair( old.x + moveX[direction] , old.y + moveY[direction] );
  }
  static int turnLeft(int direction) { 
     return (direction+1) % 4;
  }
  static int turnRight(int direction) {
     return (direction+3) % 4;
  }
}

做事必须使用更少的分配优势的这种方式,使垃圾收集器将不再需要经常运行。 另一个优点是设计仍然面向对象的,如果以后你希望能够通过例如45度的同时旋转,你可以很容易地改变方向类的感觉。

为了回答你的问题了,我认为这是完全正常的委托的方向改变类沿一定方向的坐标的任务。 流动站将只负责在这个意义上保持方向流动站对象将包含一个int字段来存储它的朝向。



Answer 2:

这是我想出了一天,而我是不相称也许喜欢一个方向枚举。 也许你会发现它在你的代码中非常有用。

import java.awt.Point;

public enum Direction {
    E(1, 0), N(0, 1), W(-1, 0), S(0, -1);
    private final int   dy;
    private final int   dx;

    private Direction(int dx, int dy) {
        this.dx = dx;
        this.dy = dy;
    }

    public Direction left() {
        return skip(1);
    }

    public Direction right() {
        return skip(3);
    }

    public Direction reverse() {
        return skip(2);
    }

    private Direction skip(int n) {
        final Direction[] values = values();
        return values[(ordinal() + n) % values.length];
    }

    public Point advance(Point point) {
        return new Point(point.x + dx, point.y + dy);
    }
}


Answer 3:

的第一件事,当我看到这个代码是方向不应该有一个字符串字段directionValue,而是一个字段,存储罗盘(即Compass.EAST,Compass.WEST)什么在我脑海中。 这将让你在MoveState.action(去掉字符串比较),因此应该使你的代码相当干净。

此外,还似乎是命名一个问题:也许北,东,西,南,并应在枚举称为方向(而不是指南针),和directionOnRight()等中的电流方向实现应该是它的静态方法(获得电流方向作为一个参数,并返回右/左/反方向)? 你并不真的需要将它们存储在额外的字段恕我直言(记得说约过早优化;-)。



Answer 4:

我在观看这种立即想到的就是一些混乱。 罗孚类有4个状态和方向,这似乎有点直觉。 我希望的位置和方向(国家我想,也许,期待,ON / OFF /充电或类似的东西)。

所以,我将调查的Java枚举 ,有一个北/南/东/西Direction为方向枚举。 (坐标)的位置具有X / Y位置和移动,我只想实现一个deltaX()deltaY()上面向枚举(它看起来像卡尔刚刚发布类似的东西)

那么你的移动代码只会是这样的:

x += facing.deltaX()
y += facing.deltaY()

哪个方向你面对。 请注意,这并不委派的运动。 罗孚一直移动,但Direction枚举给它的DX / DY通过改变。

枚举也可以有方法clockwise()counterClockwise()因此调用NORTH.clockwise()将返回新的面向值EAST 。 每个枚举实例只会有增量,顺时针/逆时针方法,以及你的Rover只是有以下几点:

private Direction facing;
private int x;
private int y;

这似乎更直观,我所期待的。 我分别表示x和y,但你可能要在一个类来包装。 如果你这样做,那么方向枚举应该处理这样的对象,而不是依赖于它被再次分开分成x和y。



Answer 5:

这似乎对我来说太复杂了。 我认为应该以这样的方式来完成:让你的机器人知道他的转向角度。 那么,如果他被要求左转或右转,他只会改变这个角度。 当他被要求移动,他将根据X这个角度移动,y坐标。 角可以存储像罗盘或与实际角度(0,90,180,270),甚至simplier。 这是很容易通过乘以对罪(角度)和cos(角度)移动步骤移动的角度方向的机器人。 为什么t it be that simple? It will also handle more directions that just 4 and you t it be that simple? It will also handle more directions that just 4 and you就可以在任何一个步骤的范围内移动。



文章来源: A question of design and object responsibility