11

在过去的几个月里,我一直在努力想出一些干净的代码来向用户报告进度。一切似乎总是归结为:

ReportProgress("Starting Task 1");
doTask1();
ReportProgress("Task 1 is done");

ReportProgress("Starting Task 2");
doTask2();
ReportProgress("Task 2 is done");

//etc... where report progress does some form of output to the user.

我内心的优秀程序员尖叫着“必须有一种更清洁的方式!” 但我很难过。有什么想法吗?

编辑 :: 我正在寻找更多关于架构信息的信息,而不是特定于实现的信息。给出的代码非常简单。

4

13 回答 13

9

将您的任务设置为事件流,并让事件处理“引擎”报告进度。如果您想走那么远,每个事件实例都可以有自己的名称、进度报告简介/模板等

如果这是一种经常发生的模式,那么值得为基础设施付出努力。完成后,可用代码可能类似于:

EventQueue tasks = new EventQueue();
tasks.Add(new TaskEvent(this.doTask1,"Foo-ing the bar"));
tasks.Add(new TaskEvent(this.doTask2,"Bar-ing the foo"));
tasks.Add(new TaskEvent(this.doTask3,"Glitching and whinging"));
...
tasks.Execute(this.ProgressEventHandler);
于 2008-11-17T22:23:50.157 回答
3

您能否使用Aspect Oriented Programming并设计一个 Progress Aspect?

有许多 AOP 实现。在 Java 世界中,最常见的两个是 AspectJ 和 Spring(使用 AspectJ 或基于代理的方面)。

于 2008-11-17T22:11:26.687 回答
3

您可以创建一个具有 name 属性和委托的 Task 类。将每个任务放在一个集合中,然后遍历它,打印消息并为每个任务调用委托。

于 2008-11-17T22:15:04.340 回答
2

这取决于即时需要多少配置,我希望代码非常通用,并通过 spring 或任何 ioc 容器设置任务。

这一切都在 spring 配置中:xml 配置将为任务对象提供其名称和参数。然后将这些任务添加到一个集合中,并将该集合交给任务运行程序。

然后,任务运行器是指示每个任务的停止和开始的代码,但是每个任务可以自由地给出它如何进行的特定状态。此外,如果出现错误,taskrunner 将捕获任何异常并继续运行。可以配置为某些任务依赖于其他任务的完成,而某些任务在失败时应该停止一切。

我不同意这里应该使用 AOP。矫枉过正。

于 2008-11-17T23:19:09.607 回答
1

在 doTask() 调用中进行报告是很自然的。
通常,报告者将是所有对象都向其发送消息的单例,报告者类负责决定是否以及在何处显示它 - 状态栏、日志文件、stderr 等。

于 2008-11-17T22:11:43.660 回答
1

假设你正在做的模式是:

  • 记录任务开始
  • 做任务
  • 记录任务结束

您可以有一个“任务”类(所有任务的父级),其 do() 方法是子类并自动记录任务的开始和结束。

只是一个想法。

于 2008-11-17T22:12:10.147 回答
1

我不会像那样手动编码显示消息的数字部分(任何时候您需要添加或删除操作或更改顺序,您都需要进行大量的剪切和粘贴操作)。您希望任何处理 ReportProgress 方法的对象在它进行时自动递增。

于 2008-11-17T22:15:23.917 回答
1

一个相当简单和干净的方法是创建一个具有do()方法和抽象 doTask() 和 getName() 方法的抽象类:

do() {
    ReportProgress("Starting " + this.getName());
    doTask();
    ReportProgress("Finished " + this.getName());
}

然后在你的任务中:

class Task1 extends Task {
    getName(){return "Task 1";}
    doTask() {
        //do stuff here
    }
}

然后你可以有一个任务,它有一个do()在一大堆其他任务上运行的 doTask() 方法。这很容易是递归的,因为任何任务都可能运行许多子任务。

于 2008-11-17T22:31:53.167 回答
1

+1 关于 AOP 建议。这是一个经典的横切关注点,AOP 可以优雅地解决。

于 2008-11-17T22:41:47.420 回答
0

您可以从 doTask 方法内部调用 ReportProgress,这可能会使它看起来更干净一些,而您只需:

doTask1();
doTask2();

报告将在这些方法中处理。

您可以使用 AOP,但在这种情况下,我的大脑会尖叫 KISS!(保持简单愚蠢)。如果这只是您正在处理的更复杂事物的简单表示,那么 AOP 可能是一种选择。

于 2008-11-17T22:14:24.497 回答
0

不幸的是,我认为最好的方法确实取决于细节——至少你使用的是什么语言。例如,在 python 中,您可以使用上下文管理器来允许编写如下代码:

with progress_report("Task 1"):
    do_task_1()

例如,即使 do_task_1() 引发异常,这也可以确保报告“任务 1 已完成”。如果您愿意,您可以单独处理异常并打印不同的内容,例如“Task 1 failed”或“Task 1 aborted”。

于 2008-11-17T23:02:25.290 回答
0

在我们的工具包中,我们有一个管理任务的任务控制器。任务作为线程运行。除了典型的线程支持外,任务还支持进度方法。一种可能的进度视图是带有标题的可视进度条,该标题指的是任务名称和任务中的步骤。为了支持可见的统计信息和状态,代码必须偶尔调用任务的进度方法。通常,这是在 for 循环中完成的,因为百分比进度可以通过当前索引除以限制来估计。

任务控制器是添加全局线程控制、状态探测、其他统计信息和性能测量挂钩的有用位置。可以通过检查控制器的状态和所有任务的状态来分析一些多线程错误和时序问题。

于 2008-11-17T23:15:28.663 回答
0

如果您使用的是 .NET,我建议您使用Enterprise Library中的 Policy Injection Application Block (最低版本:3.1)。我使用类似的东西为一个重度模拟的网站做一个“恢复到应用程序池标识”。

你可以对你的任务做同样的事情。您可以简单地定义一个带有工厂的任务类,该工厂使用企业库对象工厂构建对象,并自动向任务添加“之前”和“之后”消息。这将提供您想要的所需的优雅。

玩得开心!

于 2008-11-17T23:20:53.597 回答