views:

198

answers:

5

I have a gps device that records data e.g. datetime, latitude, longitude

I have an sdk that reads the data from the device. The way the data is read:

A command packet (basically a combination of int values in a struct) is sent to the device. The device responds with the data in fixed size chunks e.g. 64bytes

Depending on the command issued I will get back differect data structs e.g. sending command 1 to the device returns a struct like

struct x
{
 id int,
 name char[20]
}

command 2 returns a collection of the following structs (basically it boils down to an array of the structs - y[12])

struct y
{
 date datetime,
 lat decimal,
 lon decimal
}

I would then want to convert the struct to a class and save the data to a database.

What would be the best way to encapsulate the entire process, preferably using some established design pattern?

Many thanks M

A: 

Not sure if this could be covered by one single pattern. And actually I don't think it's a good approach to pick a design pattern and then implement it.

Apart from that, I think you might want to look into the Chain of Responsibility pattern. Maybe the Decorator pattern.

ilikeorangutans
A: 

I would start with base classes for commands and responses and each specific command or response derives from those.

Then a class for sending and receiving - either the command knows how to serialize itself or another paired object can do that if you want to really decouple things.

Some factory object would create the proper response type object based on parsing the response (perhaps along with knowledge of the last sent request/command)

The response object ctor takes the struct response as a parameter.

You then make a database/persistence object that knows how to tell the objects to save themselves (or you have a pairing of response objects to persistence objects for more decoupling)

There are probably better ways to do it, but the above seems reasonable to me and a lot of this I did for writing an rs232 application that talked to a medical lab device.

Tim
+1  A: 

Use a factory.

Send the query to the factory, which grabs the struct from the library. Then have it read the struct and put it into any object you want. The factory then returns the object.

An alternative is to use an adapter. Instead of just reading each field in the struct and using it to construct your model object, you might create an adapter object which contains the struct and presents the desired interface to the rest of the code. Your factory could then handle the query and return an adapted struct.

I'd shy away from the Decorator pattern. It isn't a bad pattern, but it is far more useful when you need to dynamically add or remove behavior. In this case, you haven't mentioned the need to do this dynamically, so Decorator is overkill.

On the database side, a simple data access object (DAO) will allow you to pass your model object to one of the CRUD methods. It's not the most elegant solution, but it sounds like you don't need the extra elegance of a JDO type solution.

Edwin Buck
A: 

@Ryan Elkins

By "encapsulate the entire process", I mean the process of sending a command to the device, reading the data from the device (I know the struct definition that would be returned), then converting it to an object using a class with a definition similar to the struct ( I will use the same class later for reading the records from the db) and saving the results to the db.

Btw Tim's answer is more in line with what I'm doing.

Thanks for the responses

Mmm
A: 

I had this problem before, I did a little hack using interfaces and generics and managed to do it:

// CALLER
public class Program
{
    static void Main(string[] args)
    {
        Device<Command1, S1> cmd1 = new Device<Command1, S1>();
        S1 s1 = cmd1.ExecuteCommand(new Command1());

        Device<Command2, S2> cmd2 = new Device<Command2, S2>();
        S2 s2 = cmd2.ExecuteCommand(new Command2());
    }
}

// SDK
public interface ICommand<T>
{
    T Execute();
}

public struct S1
{
    public int id;
}

public struct S2
{
    public string name;
}

public class Command1 : ICommand<S1>
{
    public S1 Execute()
    { return new S1() { id = 1 }; }
}

public class Command2 : ICommand<S2>
{
    public S2 Execute()
    { return new S2() { name = "name" }; }
}

// DEVICE
public class Device<T, U> where T : ICommand<U>
{
    public U ExecuteCommand(T cmdObject)
    {
        return cmdObject.Execute();
    }
} 
L. Cooper