如何解耦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,顺便说一句,您几乎以正确的方式创建接口 Task
或 Action
,只有一种方法 [=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 接口的实现。
我正在为服务器使用 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,顺便说一句,您几乎以正确的方式创建接口 Task
或 Action
,只有一种方法 [=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 接口的实现。