java - 单一职责原则在特定代码上的实现

标签 java solid-principles

如何分解这段代码以遵循单一职责原则?尽管我了解 SOLID 原则并阅读了许多 Material ,尤其是 Uncle Bob 关于 SOLID 原则的文章,但不幸的是我无法将以下代码拆分为两个不同的类以遵循单一职责原则。我非常感谢 StackOverflow 的帮助

/** 唯一一个充分利用 实体父类(super class)(其他类不需要 基于图 block 的 map 中的移动)。 包含与相关的所有游戏玩法 玩家。**/

package com.neet.DiamondHunter.Entity;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import com.neet.DiamondHunter.Manager.Content;
import com.neet.DiamondHunter.Manager.JukeBox;
import com.neet.DiamondHunter.TileMap.TileMap;
public class Player extends Entity {
    // sprites
    private BufferedImage[] downSprites;
    private BufferedImage[] leftSprites;
    private BufferedImage[] rightSprites;
    private BufferedImage[] upSprites;
    private BufferedImage[] downBoatSprites;
    private BufferedImage[] leftBoatSprites;
    private BufferedImage[] rightBoatSprites;
    private BufferedImage[] upBoatSprites;

    // animation
    private final int DOWN = 0;
    private final int LEFT = 1;
    private final int RIGHT = 2;
    private final int UP = 3;
    private final int DOWNBOAT = 4;
    private final int LEFTBOAT = 5;
    private final int RIGHTBOAT = 6;
    private final int UPBOAT = 7;

    // gameplay
    private int numDiamonds;
    private int totalDiamonds;
    private boolean hasBoat;
    private boolean hasAxe;
    private boolean onWater;
    private long ticks;

    // player status
    private int healthPoints;
    private boolean invincible;
    private boolean powerUp;
    private boolean speedUp;


    public Player(TileMap tm) {

        super(tm);

        width = 16;
        height = 16;
        cwidth = 12;
        cheight = 12;

        moveSpeed = 2;

        numDiamonds = 0;

        downSprites = Content.PLAYER[0];
        leftSprites = Content.PLAYER[1];
        rightSprites = Content.PLAYER[2];
        upSprites = Content.PLAYER[3];
        downBoatSprites = Content.PLAYER[4];
        leftBoatSprites = Content.PLAYER[5];
        rightBoatSprites = Content.PLAYER[6];
        upBoatSprites = Content.PLAYER[7];

        animation.setFrames(downSprites);
        animation.setDelay(10);

    }

    private void setAnimation(int i, BufferedImage[] bi, int d) {
        setAnimation(i, bi, d, false);
    }

    private void setAnimation(int i, BufferedImage[] bi, int d, boolean slowMotion) {
        currentAnimation = i;
        animation.setFrames(bi);
        animation.setDelay(d);
        slowMotion = true;
    }

    public void collectedDiamond() { numDiamonds++; }
    public int numDiamonds() { return numDiamonds; }
    public int getTotalDiamonds() { return totalDiamonds; }
    public void setTotalDiamonds(int i) { totalDiamonds = i; }

    public int getx() { return x; }
    public int gety() { return y; }
    public int getRow() { return rowTile; }
    public int getCol() { return colTile; }

    public void gotBoat() { hasBoat = true; tileMap.replace(22, 4); }
    public void gotAxe() { hasAxe = true; }
    public boolean hasBoat() { return hasBoat; }
    public boolean hasAxe() { return hasAxe; }

    public int getHealthPoints() { return healthPoints; }

    // Used to update time.
    public long getTicks() { return ticks; }

    // Keyboard input. Moves the player.
    public void setDown() {
        super.setDown();
    }
    public void setLeft() {
        super.setLeft();
    }
    public void setRight() {
        super.setRight();
    }
    public void setUp() {
        super.setUp();
    }

    // Keyboard input.
    // If Player has axe, dead trees in front
    // of the Player will be chopped down.
    public void setAction() {
        final boolean pressUPKEY = currentAnimation == UP && tileMap.getIndex(rowTile - 1, colTile) == 21;
        final boolean pressDOWNKEY = currentAnimation == DOWN && tileMap.getIndex(rowTile + 1, colTile) == 21;
        final boolean pressLEFTKEY = currentAnimation == LEFT && tileMap.getIndex(rowTile, colTile - 1) == 21;
        final boolean pressRIGHTKEY = currentAnimation == RIGHT && tileMap.getIndex(rowTile, colTile + 1) == 21;
        if(hasAxe) {
            if(pressUPKEY) {
                tileMap.setTile(rowTile - 1, colTile, 1);
            }
            if(pressDOWNKEY) {
                tileMap.setTile(rowTile + 1, colTile, 1);
            }
            if(pressLEFTKEY) {
                tileMap.setTile(rowTile, colTile - 1, 1);
            }
            if(pressRIGHTKEY) {
                tileMap.setTile(rowTile, colTile + 1, 1);
            }
            JukeBox.play("tilechange");
        }
    }

    public void update() {

        ticks++;
        boolean current = onWater;
        onWater = CheckIfOnWater();

        //if going from land to water
        if(!current && onWater){
            JukeBox.play("splash");
        }

        // set animation
        setAnimationDown();
        setAnimationLeft();
        setAnimationRight();
        setAnimationUp();

        // update position
        super.update();

    }

    public void setAnimationUp() {
        if(up) {

            if(onWater && currentAnimation != UPBOAT) {
                setAnimation(UPBOAT, upBoatSprites, 10);
            }
            else if(!onWater && currentAnimation != UP) {
                setAnimation(UP, upSprites, 10);
            }
        }
    }

    public void setAnimationRight() {
        if(right) {

            if(onWater && currentAnimation != RIGHTBOAT) {
                setAnimation(RIGHTBOAT, rightBoatSprites, 10);
            }
            else if(!onWater && currentAnimation != RIGHT) {
                setAnimation(RIGHT, rightSprites, 10);
            }
        }
    }

    public void setAnimationLeft() {
        if(left) {


            if(onWater && currentAnimation != LEFTBOAT) {
                setAnimation(LEFTBOAT, leftBoatSprites, 10);
            }
            else if(!onWater && currentAnimation != LEFT) {
                setAnimation(LEFT, leftSprites, 10);
            }
        }
    }

    public void setAnimationDown() {
        if(down) {
            if(onWater && currentAnimation != DOWNBOAT) {
                setAnimation(DOWNBOAT, downBoatSprites, 10);
            }
            else if(!onWater && currentAnimation != DOWN) {
                setAnimation(DOWN, downSprites, 10);
            }
        }
    }

    public boolean CheckIfOnWater(){
        int index = tileMap.getIndex(ydest / tileSize, xdest / tileSize);
        if(index == 4) {
            return true;
        }
        else {
            return false;
        }

    }

    // Draw Player.
    public void draw(Graphics2D g)
    {
        super.draw(g);
    }

}

最佳答案

尝试以 Model View Controller 样式实现您的组件,例如将所有与更新 View 相关的代码移动到包 yourapp.view 中,并将当前类 Player 的代码移动到新类中例如,GameBoard 或 GameView 或其他任何东西,此类的唯一职责是更新游戏板屏幕中绘制动画/图像等的模型表示。另一个类,例如 PlayerMovement 和移动与键盘事件相关的所有代码,当前在您的 Player 类中,该类的职责是捕获使玩家移动的键。

移动所有与游戏命令和目标相关的代码,并移动到另一个包 yourapp.controller 或 actions 或其他任何东西,并创建新类,例如 PlayerController、GameController 或其他,该类的唯一职责是接收玩家请求更新游戏模型状态,处理命令并告诉模型类被更新,并告诉每次模型更改时获取新模型状态的 View 类;例如,当玩家在游戏板上有一个新位置时,或者某些导弹或某些角色死亡的位置等。

例如将您的模型类放在其他包中,例如 yourapp.character 或 actors 或其他任何东西,并移动与模型状态相关的代码,创建代表游戏角色或 Actor 的新类或定义行为或角色的 Activity 元素你的游戏。例如玩家或一艘船或一门大炮等。这个类他们的责任只是定义游戏角色及其特征和行为,例如在游戏板上的位置,他们的武器,他们的力量,是活的还是死的等等,并且需要有关他们在游戏中的角色的其他信息。

尝试在第二阶段识别并应用 GoF 模式,这可以帮助您重构代码并使其更符合 SOLID 原则。

关于java - 单一职责原则在特定代码上的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40580693/

相关文章:

java - HTTP 响应 411 : Length Required when communicating with

java - Guice 场景中多个注入(inject)器引用出现是不可避免的

java - 将接口(interface)隔离原则应用于服务层接口(interface)

java - JFileChooser OK按下后如何不退出?

java - 如何判断 Linux 机器上的目录是否在 Java 中挂载了外部文件系统?

Java catch block 使用静态绑定(bind)?

c# - C#中的对象健美操一级集合规则示例?

solid-principles - 该示例如何违反 LSP,进而导致违反 OCP?

java - 澄清对 "Dependency Inversion"的理解

c# - 推荐一个设计模式