C# 丑陋的类接口定义
该类的功能: 接收一系列图像帧,序列是无限的。 检测帧中是否有运动。 根据特定算法对运动帧进行分组。 到目前为止,设计都很愚蠢:C# 丑陋的类接口定义,c#,class-design,C#,Class Design,该类的功能: 接收一系列图像帧,序列是无限的。 检测帧中是否有运动。 根据特定算法对运动帧进行分组。 到目前为止,设计都很愚蠢: class MotionDetector { //detect motion in the frame, return true if the group is captured. //frameToDispose is the frame that need be dispose, or for further process.
class MotionDetector
{
//detect motion in the frame, return true if the group is captured.
//frameToDispose is the frame that need be dispose, or for further process.
public bool ProcessFrame(Frame in, out frameToDispose);
}
消费者协会:
public void Foo()
{
bool groupCaptured = motionDetector.ProcessFrame(nextFrame, out lastFrame);
if (IsStaticFrame(lastFrame)) { lastFrame.Dispose(); }
else { imagesArray.Add(lastFrame); }
if(groupCaptured) { processImageGroup(imagesArray); }
}
我对MotionDetector的以下设计感到不舒服:
获取图像组的方法。
处理静止帧的方法。
通知客户端已捕获组的方法。
您能否就类的接口设计提供一些建议,以便客户端更容易、更优雅地使用该类?如果我正确理解了您的问题,您会不喜欢类的客户端必须使用您提供的方法的方式。。。 让框架处理类的属性而不是out参数怎么样
class MotionDetector{
public bool PreProcessFrame(Frame in);
public Frame frameToDispose{
get;
}
}
然后你可以像这样使用它:
bool groupCaptured = motionDetector.ProcessFrame(nextFrame);
if (IsStaticFrame(motionDetector.frameToDispose)){
// ...
}
否则,如果对您的应用程序有意义,您可以这样做:
class MotionDetector{
// returns frame to dispose if sucessful, null otherwise
public Frame PreProcessFrame(Frame in);
}
public class MotionDetector
{
private IFrameGroupListener m_listener;
public MotionDetector(IFrameGroupListener listener)
{
m_listener = listener;
}
public void NewFrame(Frame f)
{
if(DetectMotion(f))
{
var group = GetCaptureGroup();
m_listener.ReceiveFrameList(group);
}
}
}
public interface IFrameGroupListener
{
void ReceiveFrameList(IList<Frame> captureGroup);
}
public class FramePump
{
private MotionDetector m_detector;
public FramePump(MotionDetector detector)
{
m_detector = detector;
}
public void DoFrame()
{
Frame f = GetFrameSomehow();
m_detector.NewFrame(f);
}
}
编辑关于使用评论中建议的事件让消费者知道捕获的组:
class GroupCapturedEventArgs : EventArgs{
// put relevant information here...
}
class MotionDetector{
public event EventHandler<GroupCapturedEventArgs> GroupCaptured;
// then somewhere in your code:
private vois SomeMethod() {
// a group captured
if (GroupCaptured != null) {
GroupCaptured (this,new GroupCapturedEventArgs(/*whatever*/));
}
}
}
如果我正确理解了您的问题,那么您不喜欢您的类的客户机必须使用您提供的方法的方式。。。 让框架处理类的属性而不是out参数怎么样
class MotionDetector{
public bool PreProcessFrame(Frame in);
public Frame frameToDispose{
get;
}
}
然后你可以像这样使用它:
bool groupCaptured = motionDetector.ProcessFrame(nextFrame);
if (IsStaticFrame(motionDetector.frameToDispose)){
// ...
}
否则,如果对您的应用程序有意义,您可以这样做:
class MotionDetector{
// returns frame to dispose if sucessful, null otherwise
public Frame PreProcessFrame(Frame in);
}
public class MotionDetector
{
private IFrameGroupListener m_listener;
public MotionDetector(IFrameGroupListener listener)
{
m_listener = listener;
}
public void NewFrame(Frame f)
{
if(DetectMotion(f))
{
var group = GetCaptureGroup();
m_listener.ReceiveFrameList(group);
}
}
}
public interface IFrameGroupListener
{
void ReceiveFrameList(IList<Frame> captureGroup);
}
public class FramePump
{
private MotionDetector m_detector;
public FramePump(MotionDetector detector)
{
m_detector = detector;
}
public void DoFrame()
{
Frame f = GetFrameSomehow();
m_detector.NewFrame(f);
}
}
编辑关于使用评论中建议的事件让消费者知道捕获的组:
class GroupCapturedEventArgs : EventArgs{
// put relevant information here...
}
class MotionDetector{
public event EventHandler<GroupCapturedEventArgs> GroupCaptured;
// then somewhere in your code:
private vois SomeMethod() {
// a group captured
if (GroupCaptured != null) {
GroupCaptured (this,new GroupCapturedEventArgs(/*whatever*/));
}
}
}
消费者类正在做MotionDetector应该做的工作。也许MotionDetector构造函数或类中的某个方法应该获取帧流,并且这项工作应该在内部完成。运行算法后,该类应仅公开必需的图像数组。消费者类正在做MotionDetector应该做的工作。也许MotionDetector构造函数或类中的某个方法应该获取帧流,并且这项工作应该在内部完成。在算法运行后,类应该只公开必需的图像数组。我可能会这样做:
class MotionDetector{
// returns frame to dispose if sucessful, null otherwise
public Frame PreProcessFrame(Frame in);
}
public class MotionDetector
{
private IFrameGroupListener m_listener;
public MotionDetector(IFrameGroupListener listener)
{
m_listener = listener;
}
public void NewFrame(Frame f)
{
if(DetectMotion(f))
{
var group = GetCaptureGroup();
m_listener.ReceiveFrameList(group);
}
}
}
public interface IFrameGroupListener
{
void ReceiveFrameList(IList<Frame> captureGroup);
}
public class FramePump
{
private MotionDetector m_detector;
public FramePump(MotionDetector detector)
{
m_detector = detector;
}
public void DoFrame()
{
Frame f = GetFrameSomehow();
m_detector.NewFrame(f);
}
}
我假设DetectMotion存储帧,否则您必须将其保留在挂起列表中,直到将其清除为止。无论如何,帧泵从实际设备/文件中获取单个帧。这就是我的工作。MotionDetector负责检测运动,并将包含运动的帧组传递给FrameGroupListener,然后后者执行它需要执行的任何操作
通过这种方式,类与职责很好地分离,很少以有状态的方式完成—所有状态都本地化到单个类。由于这些调用都是无效的,如果需要,可以将它们分派到任意线程
帧泵可能会在某种计时器循环上触发
我可能会考虑将分组算法分解成一个单独的类——让MODECT检测器类将每一帧吐出一个表示是否检测到运动的布尔值,然后MOTIONGNOPER类将逐个地检测这些帧,并根据所需的任何算法吐出帧列表。“检测运动”和“确定如何对帧进行分组”显然是两项职责。但是,在这种一般的管道设计中,应该清楚地知道如何进行重构。
我可能会这样做:class MotionDetector{
// returns frame to dispose if sucessful, null otherwise
public Frame PreProcessFrame(Frame in);
}
public class MotionDetector
{
private IFrameGroupListener m_listener;
public MotionDetector(IFrameGroupListener listener)
{
m_listener = listener;
}
public void NewFrame(Frame f)
{
if(DetectMotion(f))
{
var group = GetCaptureGroup();
m_listener.ReceiveFrameList(group);
}
}
}
public interface IFrameGroupListener
{
void ReceiveFrameList(IList<Frame> captureGroup);
}
public class FramePump
{
private MotionDetector m_detector;
public FramePump(MotionDetector detector)
{
m_detector = detector;
}
public void DoFrame()
{
Frame f = GetFrameSomehow();
m_detector.NewFrame(f);
}
}
我假设DetectMotion存储帧,否则您必须将其保留在挂起列表中,直到将其清除为止。无论如何,帧泵从实际设备/文件中获取单个帧。这就是我的工作。MotionDetector负责检测运动,并将包含运动的帧组传递给FrameGroupListener,然后后者执行它需要执行的任何操作
通过这种方式,类与职责很好地分离,很少以有状态的方式完成—所有状态都本地化到单个类。由于这些调用都是无效的,如果需要,可以将它们分派到任意线程
帧泵可能会在某种计时器循环上触发
我可能会考虑将分组算法分解成一个单独的类——让MODECT检测器类将每一帧吐出一个表示是否检测到运动的布尔值,然后MOTIONGNOPER类将逐个地检测这些帧,并根据所需的任何算法吐出帧列表。“检测运动”和“确定如何对帧进行分组”显然是两项职责。但是,在这种一般的管道设计中,您应该清楚地知道如何进行重构。
您觉得不舒服的是什么?@Obalix,编辑添加了我不舒服的内容。您觉得不舒服的是什么?@Obalix,编辑添加了我不舒服的内容t、 好的一点,关于如何让消费者知道该组被捕获以及如何获取该组呢?第三个例子是最干净的,依我看。当一个简单的空测试工作原理相同且更易于维护时,人们有时会对返回布尔值感到不安。至于让消费者知道该组被捕获的问题,为什么不使用事件?@Chris,我将尝试该事件。好的一点,如何让消费者知道该组已被捕获,以及如何获取该组?第三个示例是最干净的,在我看来,当一个简单的空测试工作原理相同且更易于维护时,人们有时会对返回布尔值感到厌烦。至于让消费者知道该组已被捕获的问题,为什么不使用事件?@Chris,我将尝试该事件。对不起,帧的序列是无限的。在这种情况下,它仍然可以使用流,但暴露不可变的IList。抱歉,帧的序列是无限的。在这种情况下,它仍然可以使用流,但暴露不可变的IList。