我要写的是视图->控制器->模型->客户端->抽象的HttpRequestSender关系,因此当我使用其他平台(android-volley,Fx-SpringRest)时,可以替换HttpRequestSender 。由于在android上我需要使用一个非主线程来执行HttpRequest,因此我的解决方案是使用从控制器向下发送链的回调来启用所需的异步行为。
我的问题是,尽管这是一个可行的解决方案,但代码变得高度 很难遵循。
这样一个简单的方法,如registerDevice(String name)
-如下所示:
public class DeviceRegModel {
DeviceClient client;
DeviceInfoMgr deviceInfoMgr;
public void registerDevice(String name) throws DeviceNameTakenException {
checkIfNameTaken(name);
Device device = client.createDevice().getBody();
device.setName(name);
client.updateDevice(device);
deviceInfoMgr.set(name);
}
private void checkIfNameTaken(String name) throws DeviceNameTakenException {
for(Device dev : client.getAllDevices()) {
if(dev.getName() == name) {
throw new DeviceNameTakenException();
}
}
}
成为:
public class DeviceRegModel implements IModel {
DeviceClient client;
DeviceInfoMgr deviceInfoMgr;
public void registerDevice(String name, HttpCallback callback) {
ResponseCommand onOk = (res) -> checkIfNameTaken(name, res, callback);
HttpFailCommands onFail = callback.getOnFailCmds();
client.getAllDevices(HttpCallback.build(onOk, onFail));
}
private void checkIfNameTaken(String name, IResponse res, HttpCallback callback) {
for(Device dev : res.<Device[]>getBody()) {
if(dev.getName() == name) {
ExceptionCommand failCmd = callback.getOnFailCmds().getInternalFailCmd();
failCmd.execute(new DeviceNameTakenException());
}
}
createDevice(name,callback);
}
private void createDevice(String name, HttpCallback callback) {
ResponseCommand onOk = (res) -> setNameLocally(name, res, callback);
HttpFailCommands onFail = callback.getOnFailCmds();
client.createDevice(HttpCallback.build(onOk, onFail));
}
private void setNameLocally(String name, IResponse res, HttpCallback callback) {
Device device = res.<Device>getBody();
device.setName(name);
ResponseCommand onOk = (cmdRes) -> updateServer(name, cmdRes, callback);
HttpFailCommands onFail = callback.getOnFailCmds();
client.updateDevice(device, HttpCallback.build(onOk, onFail));
}
private void updateServer(String name, IResponse res, HttpCallback callback) {
deviceInfoMgr.set(name);
callback.getOnOkCmd().execute(res);
}
}
我正在尝试确定我是否在正确的路径上(使用第二个版本)还是应该更改我的设计?
答案 0 :(得分:1)
当您要编写可能涉及许多异步步骤的计算时,没有任何真正好的选择可以让您编写超干净的代码。
在 可用的选项中-事件驱动设计,连续传递,monad等,monad是现代选择,因为它们使您可以编写具有相同基本结构的异步代码作为等效的同步代码。它仍然不是很漂亮的代码,但至少它是由相同的功能块构建的。
在JavaScript中,异步monad是Promise,而在Java中,则是CompletionStage / CompletableFuture。这就是您的类采用这种样式的样子(我假设对client
的所有调用都是异步的,并返回CompletionStage):
DeviceClient client;
DeviceInfoMgr deviceInfoMgr;
public CompletionStage<Void> registerDevice(String name) {
return checkIfNameTaken(name)
.thenCompose( (unused) -> client.createDevice())
.thenCompose(deviceResponse -> {
Device device = deviceResponse.getBody();
device.setName(name);
return client.updateDevice(device);
}).thenApply(unused -> {
deviceInfoMgr.set(name);
return (Void)null;
});
}
private CompletionStage<Void> checkIfNameTaken(String name) {
return client.getAllDevices()
.thenCompose(devices -> {
for(Device dev : devices) {
if(dev.getName() == name) {
//I use a helper for this
CompletableFuture<Void> err = new CompletableFuture<>();
err.completeExceptionally(new DeviceNameTakenException());
return err;
}
}
return CompletableFuture.completedFuture((Void)null);
});
}
您看到它具有与以前相同的方法,并且这些方法执行与以前相同的操作,并且它们以相同的操作顺序进行操作...但是现在它们返回CompletionStage,表明它们可能异步运行,结果可能取决于这些方法返回时未完成的事情。