我正在编写一个简单的分布式java rmi应用程序,我有一堆方法,每个方法都需要遍历客户端接口的映射,以便在这些接口上调用各种其他方法,如下所示:
public void methodX (arg1, arg2) {
Iterator<String> itr = clients.keySet().iterator;
while (itr.hasNext()) {
String name = itr.next();
if (!"mod".equals(name)) {
try {
clients.get(name).methodXX(arg1, arg2);
} catch(RemoteException ex) {
// do something
}
}
}
}
public void methodY (arg1, arg2, arg3) {
Iterator<String> itr = clients.keySet().iterator;
while (itr.hasNext()) {
String name = itr.next();
if (!"mod".equals(name)) {
try {
clients.get(name).methodYY(arg1, arg2, arg3);
} catch(RemoteException ex) {
// do something
}
}
}
}
现在我修改了这些,以便它们通过传递一个名为MESSAGE_TYPE的新参数来调用单个方法doAll,如下所示:
public void methodX (arg1, arg2) {
doAll(MESSAGE_TYPE.METHODX, arg1, arg2, null);
}
public void methodY (arg1, arg2, arg3) {
doAll(MESSAGE_TYPE_METHODY, arg1, arg2, arg3);
}
doAll方法:
public void doAll(msg_type, arg1, arg2, arg3) {
Iterator<String> itr = clients.keySet().iterator;
while (itr.hasNext()) {
String name = itr.next();
if (!"mod".equals(name)) {
try {
switch(msg_type) {
case METHODX:
clients.get(name).methodXX(arg1, arg2);
break;
case METHODY:
clients.get(name).methodYY(arg1, arg2, arg3);
break;
}
} catch(RemoteException ex) {
// do something
}
}
}
}
现在还有更多像这样的方法,所以我的doAll方法需要一堆args,每个调用它的methodXX都会传递一堆空值。
我可以重写一下这样更简洁吗?如果是这样,你能提供一个例子吗?
答案 0 :(得分:9)
首先,我使用增强型for循环,并按照条目中的建议迭代条目而不是密钥:
public void doAll(arg1, arg2, arg3) {
for (Map.Entry<String,Client> entry : clients.entrySet()) {
if (!"mod".equals(entry.getKey())) {
try {
switch(MESSAGE_TYPE) {
case METHODX:
entry.getValue().methodXX(arg1, arg2);
break;
case METHODY:
entry.getValue().methodYY(arg1, arg2, arg3);
break;
}
} catch(RemoteException ex) {
// do something
}
}
}
}
我想我会重构它以传递一个“动作”来调用每个客户端,并使用来自呼叫站点的匿名内部类:
public interface RemoteAction {
public void execute(Client client) throws RemoteException;
}
public void doAll(RemoteAction action) {
for (Map.Entry<String,Client> entry : clients.entrySet()) {
if (!"mod".equals(entry.getKey())) {
try {
action.execute(entry.getValue());
} catch(RemoteException ex) {
// do something
}
}
}
}
public void methodX (final arg1, final arg2) {
doAll(new Action() {
@Override public void execute(Client client) throws RemoteException {
client.methodX(arg1, arg2);
}
});
}
public void methodY (final arg1, final arg2, final arg3) {
doAll(new Action() {
@Override public void execute(Client client) throws RemoteException {
client.methodY(arg1, arg2, arg3);
}
});
}
它不像支持lambda表达式的语言那样好,但它比switch语句更好。
答案 1 :(得分:0)
使用泛型
Iterator<String> itr = clients.keySet().iterator;
while (itr.hasNext()) {
String name = itr.next();
变为
for(String name: clients.keySet()){
此外,用switch / case替换方法并不是那么好,特别是如果你需要为未使用的值传递伪参数。保持单独的方法。
答案 2 :(得分:-1)
我不知道如何使您的方法更简洁,但我对doAll方法的参数有一些建议......
public void doAll(int methodType, Object... arg)
{
//snip
switch(msg_type)
{
case METHODX:
clients.get(name).methodXX(arg[0], arg[1]);
break;
case METHODY:
clients.get(name).methodYY(arg[0], arg[1], arg[2]);
break;
}
//snip
}
这将允许您将可变数量的args传递给doAll方法,从而减少对空值的需求。
答案 3 :(得分:-2)
根据上下文(有时安全管理器或代理人会妨碍),内省和varargs是你的朋友:
你可以拥有类似的东西:
void callStuff(String methodName, Object ... args)
{
for(Client client: clients)
{
//...filter client by name, method, etc.
//...figure out parameter types - you can guess from args or pass another parameter
Method method = client.getClass().getMethod(methodNamename, parameterTypes);
method.invoke(client,args);
}
}
(免责声明:以上代码未经测试且未编译事件 - 我不知道是否可以使用RMI)