代码之家  ›  专栏  ›  技术社区  ›  Benny

丑陋的类接口定义

  •  1
  • Benny  · 技术社区  · 15 年前

    类的功能:

    1. 接收图像帧序列,序列为 无限的 .
    2. 检测帧中是否有运动。
    3. 根据一定的算法对运动帧进行分组。

    到目前为止,设计是(相当愚蠢的):

    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);  }
    }
    

    我对运动检测器的以下设计感到不舒服:

    1. 获取图像组的方法。
    2. 处理静止框架的方法。
    3. 通知客户端已捕获组的方法。

    您能就类的接口设计给出一些建议吗,这样客户机就可以更容易、更优雅地使用这个类了?

    3 回复  |  直到 15 年前
        1
  •  1
  •   kyoryu    15 年前

    我可能会这样做:

    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()存储帧,否则您必须将其保存在一个待处理的列表中,直到需要清除它为止。无论如何,帧泵从实际设备/文件中获取单个帧。这就是工作。运动检测器负责检测运动,并将包含运动的帧组传递给framegrouplistener,然后由framegrouplistener执行所需的任何操作。

    通过这种方式,类与职责很好地分开,并且很少以有状态的方式完成——所有状态都被本地化为单个类。由于这些调用都是空的,因此如果需要,可以将它们调度到任意线程。

    框架泵可能在某种类型的计时器循环上被触发。

    我可能会考虑将分组算法分成一个单独的类——让MotionDetector类吐出每一帧,同时发出一个bool,指示是否检测到运动,然后MotionGrouper类将这些帧单独放入,并根据需要的算法吐出帧列表。”“检测运动”和“确定如何对帧进行分组”显然是两个职责。但是,在这种一般的管道设计中,应该很清楚如何进行重构。

        2
  •  3
  •   JAB    15 年前

    Consumer类正在做MotionDetector应该做的工作。也许MotionDetector构造器(或类中的某个方法)应该采用帧流,而这项工作应该在内部完成。在算法运行之后,类应该只公开必需的图像数组。

        3
  •  1
  •   Paolo Tedesco    15 年前

    如果我正确理解了你的问题,你不喜欢你的类的客户必须使用你提供的方法…
    让框架释放类的属性而不是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); 
    }
    

    编辑 关于使用评论中建议的事件让消费者知道所捕获的组:

    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*/));
        }
      }      
    }