2016-11-14 12 views
2

Как этот код можно разбить, чтобы следовать принципам принципа единой ответственности? Несмотря на то, что я понимаю принципы SOLID и прочитал многие материалы, особенно статьи дяди Боба о принципах SOLID, я, к сожалению, не смог разделить следующий код на два разных класса, чтобы следовать принципу единой ответственности. Я очень ценю помощь от StackOverflowЕдиный принцип ответственности Внедрение по конкретному коду

/** Единственный подкласс полностью использует Entity суперкласс (ни один другой класс не требует движения в карте на основе плитки). Содержит все игры, связанные с проигрывателем. **/

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

Поскольку вы прочитали много материалов от дяди Боба и хотите реорганизовать этот код, это означает, что у вас есть комплект для тестирования модулей охватывая этот класс, не так ли? – Spotted

+0

Если ваш код работает, то http://codereview.stackexchange.com/ может быть более подходящим местом для этого вопроса. – jaco0646

ответ

1

Попробуйте реализовать свои компоненты в стиле Model View Controller, например, переместить весь код, связанный с обновлением представления в пакете YourApp. например, и переместите код вашего текущего класса Player в новый класс, например GameBoard или GameView или whaterver, где единственная ответственность этого класса обновляет представления модели, рисующие анимации/изображения и т. д., на экране игровой панели , Другой класс, например PlayerMovement, и переместите весь код, связанный с событиями клавиатуры, в то время как в вашем классе Player, где ответственность этого класса захватывает ключи, которые заставляют игрока двигаться.

Переместите весь код, связанный с порядками и разрешениями игры, и перейдите в другой пакет yourapp.controller или действия или что-то еще, и создайте новые классы, например PlayerController, GameController или что-то еще, где единственная ответственность этого класса получает игрок запросы на обновление состояния игровых моделей, адресацию команд и высказывание классам моделей, которые будут обновляться, и высказывание классам, которые получают новое состояние модели каждый раз, когда изменяется модель; например, когда у игрока есть новое место на игровой доске или место для какого-либо промаха или какого-либо символа. и т. д.

Поместите свои классы моделей, например, в другую упаковку, например, yourapp.character или актеры или что угодно, и переместите код, связанный с состоянием модели, создавая новые классы, которые представляют игровые персонажи или актеры или живые элементы, которые определяют поведение или роли вашей игры. Например, игрок или корабль или пушка и т. Д. В этом классе их ответственность определяется только игровым персонажем, его характером и поведением, например, местоположение на игровом поле, их оружие, их силы, если они живы или мертвы и т. Д., И другая информация не связана с их ролью в игре.

Попробуйте определить и применить на втором этапе, шаблон GoF, это поможет вам реорганизовать ваш код и сделать его более ясным для принципов SOLID.

0

Еще одна мысль о СРП заключается в том, что каждая единица должна иметь единый разум для изменения.

Возьмите класс, каковы причины можно было бы изменить его в будущем:

  • Изменение спрайтов.
  • Анимация меняется.
  • Геймплей меняется.
  • Логика состояния игрока изменяется.

У каждого из них есть организованные поля, поэтому вы сами их заметили. Теперь просто сделайте еще один шаг и создайте классы для каждого из них. Так что вы можете изменить, например, анимацию, не касаясь кода, который влияет на геймплей.Это:

  • вносит изменения более безопасные (меньше побочных эффектов в отсутствие хорошего набора тестов)
  • делает его легче работать, вам необходимо прочитать меньше кода, а только часть вас интересует
  • Помогает вашей команде просматривать изменения (они будут знать, что вы не повлияли на игровой процесс при изменении анимации, например)
  • Упрощает работу команды в разных частях системы с меньшим шансом слияния конфликты
  • Упрощает замену одного компонента для другой реализации , вы могли бы, например, переустановить игру, заменив компонент спрайтов на другой.
+0

Вам это помогло? Пожалуйста, поддержите или примите полезные предложения. – weston