我在后台线程中运行代码,需要定期检查用户是否要中止工作。
问题是如何在大多数SOLID环境中实现它。
ICancel
界面。非const静态似乎总是会迟早产生问题。 另一方面,“标准”注射的数量正在稳步增长(ILogger,IProgressReporter,......)所以像取消一样简单的事情可能是使用静态的好选择。
还有其他/更好的方法吗?谁有经验分享?
我正在使用WPF和C#,但问题很笼罩。
以下是一个例子:
// this code is in some model assembly
public class BackgroundWorkFactory {
public IDoingBackgroundWork Worker {
get { return new DoingBackgroundWork(new Whatever()); }
}
internal class DoingBackgroundWork : IDoingBackgroundWork {
public DoingWork(IWhatever whatever) {
mWhatever = whatever;
}
public void WorkThatCanBeCanceled() {
while (!Canceled && somethingElse) {
mWhatever = whatever.DoSomthingElseThatMightAlsoAllowCancel();
...
}
}
}
// This code is in the GUI Assembly
public void StartWork() {
IDoingBackgroundWork work = factory.Worker;
Thread t = new Thread(work->WorkThatCanBeCanceled());
t.Start();
}
public void StopWork() {
// ??
}
答案 0 :(得分:0)
那么你也可以简单地在每个名为volatile
的类中创建一个UserHasWork
标志,该标志将在true时运行。如果用户取消,请检查标志并停止线程。
然而,这不能在界面中使用,但我确实发现它是执行您想要的有用方式。你总是可以在一个抽象类中使用它,但是这种方法的缺点超过了专业人员。
答案 1 :(得分:0)
IIUC,你提出静态意味着取消所有后台线程。我觉得这不够模块化,并且每个线程都应该单独取消。
OTOH,仅ICancel接口不允许太多重用。我会建议一个班级
class CancelThread{
private boolean cancelled;
synchronized void cancel(){cancelled = true;}
synchronized boolean isCancelled(){return cancelled}
}
每个线程都有其中一个,也许还有一组包含许多此类对象的全局线程。因此,要取消所有线程,您将迭代该集合并为每个线程调用取消。
答案 2 :(得分:0)
也许我在这里有点迷失,但为什么IDoingBackgroundWork不能声明一个简单的Cancel方法,而这个方法又会在基础的DoingBackgroundWorkerBase类中实现?
通过这种方式,您可以通过一种简单的方法从调用者中取消工作线程,默认实现以及修改该实现的能力。是否真的有必要使用注射剂?我认为旧的好“简单”的OO模式可以说明它。
<强>更新强>
然后我不喜欢这两种方法。我需要知道什么,他必须在某个时候优雅地停止,所以你不能只是注入代码并期望它感激地退出,静态类将添加相同级别的耦合(意味着我必须知道并使用该静态类)。 / p>
我会去定义一个ICancelable接口然后执行:
class DoingBackgroundWorkBase
{
public Cancel()
{
ICancelable cancelableWork = mWhatever as ICancelable;
if (cancelableWork != null)
cancelableWork.Cancel();
else
this.Abort();
}
}
当然
IDoingBackgroundWork work = factory.Worker;
work.Start();
这样IDoingBackgroundWork负责手动启动线程(或者可能是线程本身),并为IWwith提供“优雅的非正常”退出,以及何时不执行ICancelable。
答案 3 :(得分:0)
在尝试了几件事之后我就这样解决了。
创建了一个StopRequest类(看不到需要接口)
public class StopRequest
{
public void RequestStop() {
mIsStopRequested = true;
}
public void Reset() {
mIsStopRequested = false;
}
public static implicit operator bool(StopRequest stopRequest) {
return stopRequest.mIsStopRequested;
}
private volatile bool mIsStopRequested;
}
将此类注入需要它的每个类(或将其作为方法参数传递)
public void StartWork() {
mStopRequest = new StopRequest();
IDoingBackgroundWork work = factory.Worker(mRequestStop);
mThread = new Thread(work->WorkThatCanBeCanceled());
mThread.Start();
}
public void StopWork() {
mStopRequest.RequestStop();
mThread.Join(timeout);
}
// -----
public class BackgroundWorkFactory {
public IDoingBackgroundWork Worker(StopRequest stopRequest) {
return new DoingBackgroundWork(stopRequest, new Whatever(stopRequest));
}
}
internal class DoingBackgroundWork : IDoingBackgroundWork {
public DoingBackgroundWork(StopRequest stopRequest, IWhatever whatever) {
mStopRequest = stopRequest;
mWhatever = whatever;
}
public void WorkThatCanBeCanceled() {
while (!mStopRequest && somethingElse) {
x = mWhatever.DoSomthingElseThatMightAlsoAllowCancel();
...
}
}
}
这有以下好处
- 不需要静态/单件对象
- 只有具有取消功能的类才会受到影响
- DI框架可以自动注入它
- 单元测试时没有复杂的设置
- 轻量级/快速