2016-11-14 61 views
2

该代码如何细分以遵循单一责任原则的原则?尽管我理解SOLID原则,并且通读了许多材料,特别是Bob的叔叔关于SOLID原则的文章,但我不幸将以下代码拆分为两个不同的类,以遵循单一职责原则。我将非常感谢来自StackOverflow的帮助单一职责原则在特定代码上的实施

/**唯一的子类充分利用实体超类(其他类不需要 在基于瓦片的映射中移动)。 包含与 相关的播放器中的所有游戏。**/

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

} 
+0

由于您已经阅读了Bob的叔叔许多材料,并且想要重构此代码,这意味着您有一个单元测试套件涵盖这堂课,对吧? – Spotted

+0

如果您的代码正在工作,那么http://codereview.stackexchange.com/可能是此问题的更合适的场所。 – jaco0646

回答

1

试图实现你的组件模型视图控制器的风格,例如将所有相关的更新包中的yourapp视图中的代码。例如,将当前类Player的代码移动到一个新类中,例如GameBoard或GameView或whaterver,其中该类的单一响应性正在更新绘制动画/图像等的模型表示,在游戏板屏幕中。另一个类例如PlayerMovement并移动所有与de键盘事件相关的代码,当然在你的Player类中,这个类的响应性捕捉使得玩家移动的键。

移动所有与游戏订单和描述相关的代码并移动到另一个包yourapp.controller或actions或任何其他包中,然后创建新的类,例如PlayerController,GameController或其他类,其中该类的单一响应接收玩家请求更新游戏模型状态,寻址命令和说模型类更新,并说每次模型更改时将获取新模型状态的类;例如当玩家在游戏板中有新的位置,或者某个未命中或某个角色死亡的位置等等。

将你的模型类放在其他包中,例如yourapp.character或actors或其他类中,移动与模型状态相关的代码,创建代表游戏角色或演员的新类,或者定义游戏行为或角色的活动元素。例如玩家或船舶或加农炮等。这类他们的责任只是定义游戏角色及其特征和行为,例如游戏板中的位置,他们的武器,他们的权力,如果是生还是死等等,以及其他有关他们在游戏中的角色的信息。

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

0

另一个关于SRP的思考是每个单元都应该有一个单一的变化原因。

把你的课,什么是一个可能会改变它在未来的原因:

  • 精灵的变化。
  • 动画更改。
  • 游戏改变。
  • 玩家状态逻辑改变。

每个你有组织的领域,所以你发现他们自己。现在只需再向前走一步,为每个人创建课程。因此,您可以更改动画,而不会触及影响游戏性的代码。这:

  • 进行更改
  • 可以更轻松的工作,你需要阅读的代码更少,只有你有兴趣
  • 部分更安全(在没有好的测试套件,副作用少)
  • 让您的团队更容易查看更改(例如,他们会知道您在更改动画时并未影响游戏玩法)
  • 使团队可以更轻松地在系统的不同部分工作,同时减少合并的机会冲突
  • 可以很容易地将一个组件替换为另一个实现例如,您可以通过用另一个替换精灵组件来重新构建您的游戏
+0

这对你有帮助吗?请注意或接受有用的建议。 – weston