2016-10-10 175 views
3

我是编程新手,我想编写一个简单的客户机服务器系统,其中客户机发送命令如“SAY house”,服务器检测到关键字“SAY”作为命令并返回任何内容关键字(在本例中为“house”)。有很多例子说明如何做到这一点,但是我也希望通过这个项目来学习,这是一个很好的设计模式。我不想在Server.java和Client.java这两个类中实现一切。客户机/服务器设计模式

因此,我从一个服务器类开始,它在端口上启动服务器并等待客户端。当他从客户端获得请求时,Server类将输入委托给类“RequestHandler”。该类执行switch-case部分来检测诸如“Say”或“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是一个接口做与字符串的东西,并返回一个字符串,所以我可以将其发送回客户端。 这是好事还是应该如何设计好?

+0

向我们展示“服务器”的代码会很有用。java“,你说过你写了一个关于你如何做的一般概念。此外,你的问题的方式非常广泛,因为有很多方法可以实现你想要做的事情。 – px06

回答

3

该类做switch-case部分来检测诸如“Say” 或“SHUTDOWN”的命令并通过接口调用相应的方法。

这是一个很好的模式?

一般情况下,切换不应该使用,除非所有的情况都是敲定前手。如果我们知道有扩展,就像你的情况一样,我们应该使用switch-cases,而不是而不是

对于您的情况,您可以使用CommandStrategy作为您的需要。如果您的操作集逻辑上非常相似,请使用策略,否则命令

当我读到你的问题时,我认为命令更适合你。

我试图用命令模式实现来概述解决方案,但是很难理解一些代码片段。一般来说,只要你的代码对于阅读它的外部人来说不是很反射,你就应该使用注释。我认为你可以理解我提到的来源。

此外,如果要将客户端的字符串映射到所需的Command对象,请使用Java Map。不要使用Switch-cases或者if-else的梯子,这些梯子肯定会让它变得凌乱。如有问题,请提出问题。 :))

+0

谢谢我会尝试稍后使用命令模式。但我需要swtich case,因为服务器从客户端获得一个字符串,所以他必须区分使用哪个命令或命令模式为哪个命令加载。还是有另一种方法来分析来自客户端套接字的传入流并用正确的命令进行响应? – mrprinze

+0

您可以使用地图跳过开关盒。映射映射。现在,您可以通过从客户端获得的字符串获得所需的命令对象。 map.get(“someString”):))希望你明白。 –

+0

非常感谢帮助。好吧,我现在是以下设计好吗?: 一个类**服务器**与一个套接字启动一个服务器,并等待客户端连接。客户端连接后,他创建一个新的线程就像我上面的代码(** CommandHandler **)。现在** CommandHandler **是调用者。然后我有一个**命令**界面和**混凝土**命令类。具体类调用实际实现** real **发送消息给客户端的类。这是正确的吗?因为使用模式,我不知道谁是我的例子 – mrprinze