客户端/服务器设计模式

3
我是编程新手,想编写一个简单的客户端服务器系统,其中客户端发送命令,如“SAY house”,服务器将“SAY”关键字识别为命令,并返回关键字后面的所有内容(在这种情况下为“house”)。虽然有很多示例可以做到这一点,但我还想通过这个项目学习解决此类问题的良好设计模式。我不想只用Server.java和Client.java两个类来实现所有东西。
所以,我从一个Server类开始,它在一个端口上启动服务器并等待客户端。当他从客户端收到请求时,Server类将输入委托给一个名为“RequestHandler”的类。该类通过switch-case部分检测命令,例如“Say”或“SHUTDOWN”,并通过接口调用相应的方法。
这是一个好的模式吗?例如,“SHUTDOWN”服务的问题是,我必须始终带着Socket对象到执行命令的方法中。或者也许这种模式对于升级具有更多功能的服务器来说并不好?请帮助改进!
谢谢
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是一个接口,用于对字符串进行操作并返回一个字符串,以便我可以将其发送回客户端。这个设计是否良好?


能否给我们展示一下你所说的已经编写的Server.java代码,以便我们对你的实现方式有一个大致的了解。此外,你的问题比较宽泛,因为有很多方法可以实现你想要做的事情。 - px06
1个回答

6
这个类执行switch-case部分来检测像"Say"或者"SHUTDOWN"这样的命令,并调用相应的方法。这是一个好的模式吗?
通常情况下,除非所有的情况都在之前确定,否则不应使用switch case。如果我们知道有扩展,就像你的情况一样,我们根本不应该使用switch case。
对于你的情况,你可以根据需要使用CommandStrategy。如果你的操作集在逻辑上非常相似,那么就选择Strategy,否则选择Command
根据我阅读你的问题,我认为Command更适合你。
我尝试用Command模式实现了解决方案,但有些代码片段很难理解。通常情况下,当你的代码对外部人员来说不太反映时,应该使用注释。我想你可以通过我提到的源代码来理解。
此外,如果您想将客户端的字符串映射到所需的Command对象,请使用Java Map。不要使用Switch-case或if-else梯子,这会使其变得混乱。如果有任何问题,请提出。:))

谢谢,这帮了我很多。好的,现在我设计的是以下内容:一个名为Server的类,它具有一个Socket来启动服务器并等待客户端连接。当客户端连接后,他会像上面我的代码一样创建一个新的线程(CommandHandler)。现在CommandHandler是调用者。然后我有一个Command接口和concrete命令类。具体的类调用实际实现向客户端发送消息的类。这样做对吗?因为使用这种模式,我不知道在我的情况下谁是谁。 - hadamard
命令模式的主要重点是将某个操作的实际实现与其使用者解耦。在您的示例中,如果您正在执行类似以下代码的操作,则这是整个想法。public void performCommand(String commandName, String input){ Command command = map.get(commandName); command.setInput(input); command.execute(); }。现在,您的代码非常易于扩展。只需在有新命令时引入新的命令对象即可。 :)) - Supun Wijerathne
那么Map<String,Command>怎么办?谁应该知道这个映射以获取命令? - hadamard
你的描述总体上很好。你说的“who should know?”是什么意思? - Supun Wijerathne
谁应该有地图访问权限?知道调用者(CommandHandler)有权访问地图,并可以从中获取命令以调用命令。我认为这应该是正确的。 但是感谢您,我认为我的主要设计问题已经解决了。 - hadamard
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接