0

I am building a processing library that will process measurement data from a senor. Depending on the sensor application, the data may be processed in different ways. The output of the processing may contain 1, 2, or 3 output values depending on the processing type.

I have created several enum's and interface's. These are the key types:

public enum ProcessingType
{
    Default = 0,
    Type1 = 1, 
    Type2 = 2
}

public interface IProcessItem
{
    ProcessingType GetProcessingType();
}

public interface IProcessInputs
{
    string GetID();
    float GetTemperature();
    IEnumerable<byte> GetProcessData();
}

I am basically designing an API that will have to be documented and implemented by another application. My process library will have a single threaded processing queue (like here) managed by a singleton (like the Multithreaded Singleton example here).

The application using this library spins up a new thread for each connection to a sensor; at the end of the connection it will put the retrieved data into an object, pass it to my processing queue, and kill the communication thread. The application should not need to wait for the processor to finish before killing the comm. thread.

The singleton and the queue will accept IProcessItem's:

//Singleton
public sealed class SignalProcessor
{
    //...
    public static SignalProcessor Processor
    {
        get
        {
            //...
            lock (syncRoot)
            {
                processor = new SignalProcessor();
            }
            return processor;
        }
    }

    public void Process(IProcessItem item)
    {
        processQueue.Enqueue(item);
    }
}

//Queue
internal sealed class ProcessQueue : IDisposable
{
    //...
    public void Enqueue(IProcessItem item)
    {
        //add to async queue
    }
}

//Usage
var po = new ProcessObject();
SignalProcessor.Processor.Process(po);
//...complete and kill thread

The concrete object that is passed from the application should have everything it needs to provide the requested data to the measurement data processor, then save the results back into some kind of persistent storage.

Creating the interface for the input is easy because they are all the same. However, I cannot figure out how to handle the output. I have started creating interfaces for the output types:

public interface IProcessOutput1
{
    float Level1 { get; set; }
    SaveData();
}
public interface IProcessOutput2
{
    float Level1 { get; set; }
    float Level2 { get; set; }
    SaveData();
}
//etc

But if my processing engine takes an object that implements IProcessInputs, how do save the output values back into the object?

What I can't figure out is should I make them have to implement multiple interfaces on that object like:

internal class ProcessObject1 : IProcessItem, IProcessInputs, IProcessOutput1
{
    //interface implementations
}

internal class ProcessObject2 : IProcessItem, IProcessInputs, IProcessOutput2
{
    //interface implementations
}

Or if I should combine the interfaces into one for each processing type:

public interface IProcessType2 : IProcessItem
{
    int GetID();
    float GetTemp();
    float Level1 { get; set; }
    float Level2 { get; set; }
    SaveData();
}
//etc.
Community
  • 1
  • 1
jwatts1980
  • 7,254
  • 2
  • 28
  • 44

2 Answers2

1

Not sure I am following 100% but sounds like a factory pattern that takes in the ProcessingType enum as a parameter might meet your needs. Something like...

public interface IProcessorFactory
{
  IProcessor Create(ProcessingType type);
}

internal class ProcessorFactory : IProcessorFactory
{
  IProcessor Create(ProcessingType type)
  {
    IProcessor processor = null;
    // switch statement or perhaps indivual factory implementations for each processor type.
    // pick your poison
    switch(type)
    {
      case ProcessingType.Default:
        processor = new DefaultProcessor();
        break;
      ... etc.
    }

    return processor;
  }
}

public interface IProcessor
{
    int GetID();
    float Value { get; set; }
    void SaveData();
}

internal class DefaultProcessor : IProcessor
{
  float Value { get; set; }

  int GetID()
  {
    ...
  }

  void SaveData()
  {
    ...
  }
}
Trevor Ash
  • 623
  • 4
  • 8
  • I apologize for not being clear in my question.. it's pretty fuzzy idea in my head too... I'm not really sure how to implement what I need. I'll look over your answer and see if it will help. Thanks! – jwatts1980 Nov 18 '14 at 18:49
  • Sure, and in case it's not 100% clear. The client would use the IProcessorFactory to create an instance of the appropriate IProcessor. – Trevor Ash Nov 18 '14 at 18:59
  • +1 for a good idea. I spent time today studying up on the Factory pattern. It seems like the concrete type(s) will have to be created in the server application because there will be custom implementation required to retrieve the data inputs and then to save the outputs. The factory pattern could be used in the server app to create the correct type, but I don't think it will help me in the process library. – jwatts1980 Nov 19 '14 at 02:48
0

I ended up using the method of 1 process type interface for each processing type. For the processing type enumeration

public enum ProcessingType
{
    Default = 0,
    Type1 = 1, 
    Type2 = 2
}

I created an interface for each one:

public interface IProcessingTypeDefault {
    //...
}

public interface IProcessingTypeType1 {
    //...
}

public interface IProcessingTypeType2 {
    //...
}

Since each processing type had similar and different inputs/outputs I thought I could optimize the interfaces. But I realized that trying to optimize the number and content of each interface was going to be too complicated, especially in light of potential changes down the road that could negate the optimization.

jwatts1980
  • 7,254
  • 2
  • 28
  • 44