Client/Server 设计模式
Client/Server design pattern
我是编程新手,我想编写一个简单的客户端服务器系统,其中客户端发送 "SAY house" 之类的命令,服务器检测关键字 "SAY" 作为命令和 returns 关键字后面的任何内容(在本例中为 "house")。有很多如何执行此操作的示例,但我还想通过该项目学习的是解决此类问题的良好设计模式。我不想在 class 和 Client.java.
这样的 2 class 中实现所有内容
所以我从服务器 class 开始,它在端口上启动服务器并等待客户端。当他从客户端收到请求时,服务器 class 将输入委托给 class "RequestHandler"。 class 执行 switch-case 部分来检测像 "Say" 或 "SHUTDOWN" 这样的命令,并通过接口调用相应的方法。
这个模式好吗?例如,问题是服务 "SHUTDOWN"。我必须将套接字对象一直带到执行命令的方法中。或者,也许这种模式不适合升级具有更多功能的服务器?请帮助改进!
谢谢
public class Server {
private int port;
private ServerSocket server;
public Server(int port) throws Exception{
this.port = port;
try{
server = new ServerSocket(port);
}catch(Exception e){
System.out.println("Server kann nicht gestartet werden: "+e.getMessage());
throw e;
}
}
public Server(int port){
this.port = port;
}
public void start(){
Socket client;
Thread thread;
while (true) {
try {
client = server.accept();
// Verbindung eingegangen, Objekt erzeugen und in Thread laufen lassen
System.out.println("Verbindung von "+client.getInetAddress());
CommandHandler handler = new CommandHandlerImpl(client,new ControllerImpl());
thread = new Thread(handler);
thread.start();
}
catch (Exception e) {
System.out.println("Verbindungsfehler: "+e);
}
}
}
}
public class CommandHandlerImpl implements CommandHandler{
private final String regex = " ";
private IController controller;
private Socket client;
public CommandHandlerImpl(Socket client, IController controller){
this.client = client;
this.controller = controller;
}
@Override
public String getCommand(String abstractString) throws Exception {
String result;
String[] arr = abstractString.split(regex);
String command = arr[0];
String s = "";
if(arr.length > 1){
s = arr[1];
}
switch (command) {
case "CAPITALIZE":
result = controller.capitalize(s);
break;
case "BYE":
result = controller.sayBye();
break;
case "SHUTDOWN":
result = controller.shutdown(s);
break;
default:
result="Command nicht gefunden!!!";
}
return result;
}
@Override
public void run() {
String line, res;
try {
PrintWriter out = new PrintWriter(client.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
while (true) {
line = in.readLine();
System.out.println(line);
res = null;
if (line != null){
res = getCommand(line);
}
if (res == null){
break;
}
out.println(res);
out.flush();
}
System.out.println("Verbindung von "+client.getInetAddress()+" beenden.");
client.close();
} catch (IOException e) {
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
}
}
IController 是一个使用 String 和 returns String 做某事的接口,因此我可以将它发送回客户端。
这样好还是好的设计应该如何?
This class does the switch-case part to detect a command like "Say"
or "SHUTDOWN" and calls over an interface the corresponding method.
Is this a good pattern?
一般情况下不应使用 switch case,除非所有 case 都事先最终确定。如果我们知道有扩展,就像你的情况一样,我们应该 不 使用 switch-cases。
对于您的情况,您可以根据需要使用 Command or Strategy。如果您的操作集在逻辑上非常相似,请使用 Strategy,否则使用 Command。
看了你的问题,我觉得 Command 更适合你。
我试图概述使用命令模式实现的解决方案,但有点难以理解您的某些代码片段。通常,只要您的代码对于阅读它的局外人来说没有太多反映,您就应该使用注释。我想你可以理解我提到的来源。
此外,如果您想将来自客户端的字符串映射到所需的命令对象,请使用 Java 映射。不要使用 Switch-cases 或 if-else 梯子,这肯定会使它变得混乱。如有问题请提出。 :))
我是编程新手,我想编写一个简单的客户端服务器系统,其中客户端发送 "SAY house" 之类的命令,服务器检测关键字 "SAY" 作为命令和 returns 关键字后面的任何内容(在本例中为 "house")。有很多如何执行此操作的示例,但我还想通过该项目学习的是解决此类问题的良好设计模式。我不想在 class 和 Client.java.
这样的 2 class 中实现所有内容所以我从服务器 class 开始,它在端口上启动服务器并等待客户端。当他从客户端收到请求时,服务器 class 将输入委托给 class "RequestHandler"。 class 执行 switch-case 部分来检测像 "Say" 或 "SHUTDOWN" 这样的命令,并通过接口调用相应的方法。
这个模式好吗?例如,问题是服务 "SHUTDOWN"。我必须将套接字对象一直带到执行命令的方法中。或者,也许这种模式不适合升级具有更多功能的服务器?请帮助改进!
谢谢
public class Server {
private int port;
private ServerSocket server;
public Server(int port) throws Exception{
this.port = port;
try{
server = new ServerSocket(port);
}catch(Exception e){
System.out.println("Server kann nicht gestartet werden: "+e.getMessage());
throw e;
}
}
public Server(int port){
this.port = port;
}
public void start(){
Socket client;
Thread thread;
while (true) {
try {
client = server.accept();
// Verbindung eingegangen, Objekt erzeugen und in Thread laufen lassen
System.out.println("Verbindung von "+client.getInetAddress());
CommandHandler handler = new CommandHandlerImpl(client,new ControllerImpl());
thread = new Thread(handler);
thread.start();
}
catch (Exception e) {
System.out.println("Verbindungsfehler: "+e);
}
}
}
}
public class CommandHandlerImpl implements CommandHandler{
private final String regex = " ";
private IController controller;
private Socket client;
public CommandHandlerImpl(Socket client, IController controller){
this.client = client;
this.controller = controller;
}
@Override
public String getCommand(String abstractString) throws Exception {
String result;
String[] arr = abstractString.split(regex);
String command = arr[0];
String s = "";
if(arr.length > 1){
s = arr[1];
}
switch (command) {
case "CAPITALIZE":
result = controller.capitalize(s);
break;
case "BYE":
result = controller.sayBye();
break;
case "SHUTDOWN":
result = controller.shutdown(s);
break;
default:
result="Command nicht gefunden!!!";
}
return result;
}
@Override
public void run() {
String line, res;
try {
PrintWriter out = new PrintWriter(client.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
while (true) {
line = in.readLine();
System.out.println(line);
res = null;
if (line != null){
res = getCommand(line);
}
if (res == null){
break;
}
out.println(res);
out.flush();
}
System.out.println("Verbindung von "+client.getInetAddress()+" beenden.");
client.close();
} catch (IOException e) {
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
}
}
IController 是一个使用 String 和 returns String 做某事的接口,因此我可以将它发送回客户端。 这样好还是好的设计应该如何?
This class does the switch-case part to detect a command like "Say" or "SHUTDOWN" and calls over an interface the corresponding method.
Is this a good pattern?
一般情况下不应使用 switch case,除非所有 case 都事先最终确定。如果我们知道有扩展,就像你的情况一样,我们应该 不 使用 switch-cases。
对于您的情况,您可以根据需要使用 Command or Strategy。如果您的操作集在逻辑上非常相似,请使用 Strategy,否则使用 Command。
看了你的问题,我觉得 Command 更适合你。
我试图概述使用命令模式实现的解决方案,但有点难以理解您的某些代码片段。通常,只要您的代码对于阅读它的局外人来说没有太多反映,您就应该使用注释。我想你可以理解我提到的来源。
此外,如果您想将来自客户端的字符串映射到所需的命令对象,请使用 Java 映射。不要使用 Switch-cases 或 if-else 梯子,这肯定会使它变得混乱。如有问题请提出。 :))