Некрасивое определение интерфейса класса - PullRequest
1 голос
/ 04 марта 2010

Функция класса:

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

Я чувствую себя некомфортно из-за дизайна MotionDetector следующего содержания:

  1. Способ получения группы изображений.
  2. Способ утилизации неподвижной рамы.
  3. Способ уведомления клиента о захвате группы.

Можете ли вы дать несколько советов по дизайну интерфейса класса, чтобы клиенту было проще и элегантнее использовать этот класс?

Ответы [ 3 ]

3 голосов
/ 04 марта 2010

Класс потребителя выполняет ту работу, которую должен выполнять MotionDetector. Возможно, конструктор MotionDetector (или некоторый метод в классе) должен принимать поток кадров, и эта работа должна выполняться внутри. Класс должен предоставлять только необходимый массив изображений после запуска алгоритма.

1 голос
/ 04 марта 2010

Я бы, вероятно, сделал что-то вроде этого:

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 () хранит кадр, в противном случае вам придется держать его в списке ожидания, пока не настало времяизбавиться от этого.В любом случае, FramePump получает отдельные кадры из фактического устройства / файла.Это работа.MotionDetector отвечает за обнаружение движения и передачу групп кадров с движением в них в FrameGroupListener, который затем делает все, что ему нужно.

Таким образом, классы хорошо разделены обязанностями, и очень малоделается с учетом состояния - все состояние локализовано для отдельных классов.Поскольку все вызовы являются недействительными, они могут быть отправлены в произвольные потоки, если вам нужно.

Вероятно, FramePump запускается в каком-то цикле таймера.

Я, вероятно, рассмотрю возможность прерываниятакже алгоритм группировки в отдельный класс - пусть класс motiondetector выкладывает каждый кадр вместе с булом, указывающим, было ли обнаружено движение, а затем класс MotionGrouper будет принимать их отдельно и выплевывать списки кадров в соответствии с любым алгоритмом.желательно«Обнаружение движения» и «определение того, как группировать кадры» - это, безусловно, две обязанности.Но должно быть ясно, как вы будете выполнять этот рефакторинг в этом общем виде конвейера.

1 голос
/ 04 марта 2010

Если я правильно понял ваш вопрос, вам не нравится, как клиент вашего класса должен использовать метод, который вы предоставляете ...
Как насчет того, чтобы заставить фрейм распоряжаться свойством класса вместо параметра 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*/));
    }
  }      
}
...