如何解耦java中的数据和行为对象?

How to decouple data and behavior objects in java?

我正在为服务器使用 Java 构建多人游戏。目前,我使用单个 class 文件来存储播放器数据和处理数据。我是初学者,所以我不知道这是一种不好的做法。 http://howtodoinjava.com/best-practices/5-class-design-principles-solid-in-java/ 这篇文章帮助我了解我违反了 'Single Responsibility principle' 的规则。

这就是我的代码现在的样子。

public class PlayerSession{

    String playerId;
    String playerName;

    // 20+ player data fields, which I am trying to reduce
    // and keep only the most used data

    public void messageProcessor(JSONObject clientRequest) throws JSONException{

        switch(clientRequest.getString("task")){            
        case "login": loginProcess(); break;
        case "logout": logoutProcess(); break;

        //50+ different actions 
        }
    }

    public void populateSessionData(String playerId){
        // populate player data from database
    }

    private void loginProcess(){
        //Process login
    }

    private void logoutProcess(){
        //Process logout
    }

    //20+ other methods which do entirely different tasks.
}

随着我们添加更多功能,class 将变得极难维护和修改。现在我试图将这个 class 分离成两个不同的 class。一个,仅用于存储玩家数据,另一个用于处理如下所示的行为。

public class PlayerSession {

    final TaskHandler taskHandler = new TaskHandler();

    public void messageProcessor(JSONObject clientRequest) throws JSONException {

        switch (clientRequest.getString("task")) {
        case "login":
            taskHandler.loginProcess();
            break;
        case "logout":
            taskHandler.logoutProcess();
            break;

        // 50+ different actions
        }
    }
}

public class PlayerData {

    String playerId;
    String playerName;

    // 20+ player data fields, which I am trying to reduce
    // and keep only the most used data

    public void populateSessionData(String playerId) {
        // populate player data from database
    }
}

public class TaskHandler {

    final PlayerData player = new PlayerData();

    private void loginProcess() {
        // Process login
    }

    private void logoutProcess() {
        // Process logout
    }

    // 20+ other methods which do entirely different tasks.
}

并且此设计导致为单个客户端创建 2 个额外的对象,即 PlayerData 和 TaskHandler。对于 10,000 个并发客户端的服务器,这会成为一个问题吗?这是正确的方法吗?如果不是,对于这种情况,最好的方法是什么?

我在某处读到,仅用于保存数据的对象并不是一个好方法。是吗?

你需要在这里做很多事情:

PlayerSession class:

为什么要在这里解析JsonObject?您需要创建名为 ClientRequest 的 class,所有工作都将在其中完成。将所有你需要的从客户端请求到这个 class 并且只有那些准备好使用的方法 something 不要从对象中提取数据并在你的手动计算代码这是程序方式。同时将 PlayerSession 重命名为 Session.

玩家数据class

首先将其重命名为Player class它代表Player而不是Player数据。不要在 Player 中执行任何数据库关系操作。同样在创建之后你需要准备好使用 Player,在这里你创建实例然后用数据填充它,最好在构造函数中完成。

任务处理程序class

不要创建做很多事情的 class,顺便说一句,您几乎以正确的方式创建接口 TaskAction,只有一种方法 [=18] =] 并创建许多实现,如 LoginTask, LogoutTask 等。也许你需要有结构来为你提供特定操作的实例,这也有助于摆脱手动创建具体实现,你将以更多的多态方式来实现。

public class Session {

    private final SessionActions actions;
    private final RequestFabric requests;
    private final Player player;

    public Session (SessionActionFabric actionsFabric,
                    RequestFabric requests, Player player) {
        this.actionsFabric = actionsFabric;
        this.requests = request;
        this.player = player;
    }

    void login() throws LoginException {
        Request request = request.createRequest();
        SessionAction login = actions.createActions("login", player, request);
        login.performAction();
        //something like that it's depends on whole picture of your project and maybe changed
    }

    //etc.
}

public interface Request {

    public performRequest(Player player, /*request data your api specs here*/) throws RequestException;
}

public class Player {

    private String id;
    private String name;

   public Player(String id, String name){
       this.id = id;
       this.name = name;
   }

   //getters, setters 
}

interface SessionAction {

    void performAction() throws SessionActionException;
}

class LoginAction implements SessionAction {
    private final Player player;
    private final Request request;


    LoginAction (Player player, Request request) {
        this.player = player;
        this.request = request;
    }

    void performAction() {
        // do you things here
    }

}

Q 对于 10,000 个并发客户端的服务器,这会成为问题吗?这是正确的方法吗?如果不是,对于这种情况,最好的方法是什么?

A 不要介意性能最好注意好的设计,如果你有性能问题,你几乎总能找到通过好的设计来改进它的方法(缓存,池化等)

Q我在某处读到,仅用于保存数据的对象并不是一个好方法。是吗?

A你说得对,这个叫做贫血模型,(数据和处理它的方法是分开的)但是现在很流行。

基于您与 Joy 的讨论。如果你担心像 LoginAction 这样的 Action class 会每 2 秒创建一次。使用单例模式,具有静态最终动作实例 class 和该实例的静态 getter (LoginAction.getInstanceOfLoginAction()) 并且每次都使用它而不是创建新的。但是请确保您的操作 class 是无状态的而不是有状态的!!

class LoginAction implements SessionAction {
  private static final LoginAction loginAction = new LoginAction();
  public static LoginAction getLoginAction() {
      return loginAction;
  }

  void performAction(Player player, Request request) {
    // do you things here
  }

}

还有一件事是使用工厂(参见工厂模式)根据请求获取 Action 接口的实现。