0

要件: Java のソケット API によって TCP サーバーを実装します。サーバーは同時に複数のクライアントを処理できます。サーバーは、XML テキスト ファイルに (データ ストレージとして) 項目を追加/削除できます。クライアントは、"addItem"/"removeItem" のようなコマンドをサーバーに送信できます。クライアントが "addItem" を送信した場合、新しいノードを XML ドキュメントに追加する必要があります。

コマンド設計パターンを使用する必要がありますか? もしそうなら、コマンド、レシーバー、インボーカー、クライアントのどれがいいですか?

私の実装は以下のようなものです(コメントのいくつかの質問も):

interface Command{
    public void execute();
}

AddItemCommand implements Command{

    //The receiver
    XMLFileHelper xmlHelper;

    //The data need to added to XML file
    //This data should be here or not??
    ItemNode addedNode;

    public AddItemCommand(XMLFileHelper newHelper){
        xmlHelper = newHelper;
    }

    public void execute(){
        xmlHelper.addItemNode(addedNode);
    }

}

/*this class will handle all the xml doc operation: add, remove ...
i guess, it is should be the receiver
DataHelper in the parent interface, subclass could be XMLFileHelper,  DBHelper,         MessageQueueHelper ...
*/
public class XMLFileHelper implements DataHelper{

}

RemoveItemCommand implements Command(){
    //...............
}

/*This is the invoker, i am not sure what should it be, so i do not have a good name for it.*/
public class Invoker{
    Map<String, Command> map = new HashMap<String, Command>();

    public void addCommand(String cmdName, Command c){
        map.put(cmdName, c);
    }


    public void processRequest(String reqName){
        map.get(reqName).execute();
   }

}

TcpServerThread implements Runable{

    public void run(){
        DataHelper xmlPaser = new XMLFileHelper();
        Command cmd1 = new AddItemCommand();
        Command cmd2 = new RemoveItemCommand();

        Invoker invoker = new Involer();
        invoker.addCmd("add", cmd1);
        invoker.addCmd("remove", cmd2);

        String cmdName = getCommandName(socket.getInputStream());

        invoker.processRequest(cmdName);


    }
}
4

2 に答える 2

1

あなたが尋ねようとしている主な質問が何であるかはわかりませんが、私の直感は、あなたのアプローチが良いかどうかについて、何らかの確認を求めていることを示しています.

これに答えるには、このアプリの要件は何かを考える必要があります。TcpServer をアプリケーションの中心点にし、このトランザクションでクライアントにいくつかのサービスを提供する唯一の側にし、集中型ストレージが必要な場合、このアプローチはまったく問題ありません。あなたの設計により、コードのほぼすべてのユニットを簡単にテストできます (唯一の例外は、実行メソッドで実行しすぎて依存関係が隠されている TcpServerThread です。つまり、コマンドを初期化し、それらを Invoker に追加して実行します。分割します。ロジックを初期化して実行するものと、Invoker は外部から注入されます. Invoker のセットアップのジョブは別の場所で実行されます )

コマンドパターンはここに非常に適していると思います。コマンド インターフェイスを次のように変更することも検討できます。

interface Command{
  void execute();
}

のようなものに

interface Command{
  ResponseType execute( Parameters params );
}

ResonseType を使用すると、フィードバックをクライアントに渡すことができます。また、パラメータ型を注入して実行すると、パラメータを使用してリクエストを管理できます。

次に、Invoker クラスに注目しましょう。あなたは名前が良いかどうかについて尋ねました。適切な記述名を見つけようとするとき、私が常にたどるプロセスは、「このクラスの主な目的は何ですか?」という質問をすることです。あなたの場合、Invoker はコマンド (CommandRegister ?) を HashMap に保存しており、別のレイヤーも導入しているため、TcpServer はコマンドを直接呼び出していません。そのため、クラスに対する別の責任のように感じます。Invoker を processRequest にする必要がありますか? コマンドを実行する前に、追加の作業を実行する予定はありますか? そうでない場合は、Invoker を次のようなものに置き換えるとよいでしょう。

class CommandRegister{
    Map<String, Command> map = new HashMap<String, Command>();

    public void addCommand(String cmdName, Command c){
        map.put(cmdName, c);
    }


    public Command getCommand(String reqName){
        return map.contains(reqName) ? map.get(reqName) : null;
   }
}

次に、TcpServer は execute を直接呼び出します。メリットは何ですか?実行をリファクタリングしてパラメーターを提供する場合は、変更する場所が 1 つ少なくなります。テストするスポットが 1 つ少なくなります。また、クラスに対する追加の責任はありません。また、名前がよりわかりやすいものになりました。将来、TcpServer がコマンドを実行するために使用する別のレイヤーをいつでも持つことができます。例えば:

class CommandInvoker{
  public CommandInvoker(CommandRegister cR){
    this.cR = cR;
  }

  public void execute(String cmdName){
     Command cmd = cR.get(cmdName);
     cmd.execute(); //if you decided like me to return null if there is no Command with specific name in register you should also check if cmd is not null before calling execute.
  }
}

ただし、アプリが単純なものであり、コマンド実行レイヤーで追加の作業を行う予定がない場合は、いつでも Invoker を使用できます。

何か不明な点があれば教えてください。明確にしようとします;)

于 2013-11-05T14:11:17.777 に答える
0

@ルーク:はい、確認を求めています。私はJavaでコマンドパターンを学びたいと思っているので、ここでコマンドパターンを使用する必要があるかどうかわかりません。コマンドパターンのより現実的な例をグーグルで検索しようとしていますが、非常に単純なデモがいくつか見つかりました。したがって、単純な TCP サーバーを実装してみてください。後で、Tomcat のソース コードを見て、コマンド パターンを使用している場合は、サーバーの設計と実装方法を確認しようとします。あなたが言ったように、コマンドパターンはここに収まります。ありがとうございます。しかし、クライアントが接続しようとすると、1 つのスレッド (ソケット obj を使用) を使用して同じスレッドからのすべての要求を処理する予定であるため、コマンドと呼び出し元オブジェクトの構築をスレッドの実行メソッドに配置する必要があることを恐れています。クライアント。そのため、クライアントが送信したコマンドを知っているのはスレッドだけです。

于 2013-11-06T06:04:43.280 に答える