views:

805

answers:

5

Hi there, thanks in advance for your help. I am wondering if there is a (design) pattern that can be applied to this problem.

I am looking to parse, process, and extract out values from text files with similar, but differing formats.

More specifically, I am building a processing engine that accepts Online Poker Hand History files from a multitude of different websites and parses out specific data fields (Hand #, DateTime, Players). I will need the logic to parse the files to be slightly different for each format, but the processing of the extracted values will be the same.

My first thought would be to create just 1 class that accepts a "schema" for each file type and parses/processes accordingly. I am sure there is a better solution to this.

Thanks!

Bonus Point: Any specific implementation hints in C#.

+1  A: 

The "Provider" pattern is the one you're looking for... it is what is used in ADO.Net. Each database vendor has a separate data "Provider" that "knows" how to read the data from it's specific DB vendors product, but delivers it in a standard format (interface) to downstream systems... You will write a small "Provider" component (a single class will suffice) that "knows" the format for each of your different website poker history data providers, and exposes that data in exactly the same way to the upstream system that reads it...

Charles Bretana
A: 

First, create your "Online Poker Hand History" model. This model will represent the data and will be able to process this data independently from the source. Then create providers for each of the different source formats that must be capable of converting the file's information into the model.

EDIT: e.g.

public interface IDataProvider
{
    IOnlinePokerInfo ParseFileInformation(FileInfo input);
}

public interface IOnlinePokerInfo
{
    int Hand { get; set; }
    DateTime DateInfo { get; set; }
    List<IPlayer> Players { get; set; }
    void ProcessInformation();
}

public interface IPlayer
{
    string Name { get; set; }
}

public class MyOnlinePokerInfo : IOnlinePokerInfo
{
    private int hand;
    private DateTime date;
    private List<IPlayer> players;

    public int Hand { get { return hand; } set { hand = value; } }
    public DateTime DateInfo { get { return date; } set { date = value; } }
    public List<IPlayer> Players { get { return players; } set { players = value; } }

    public MyOnlinePokerInfo(int hand, DateTime date)
    {
        this.hand = hand;
        this.date = date;
        players = new List<IPlayer>();
    }

    public MyOnlinePokerInfo(int hand, DateTime date, List<IPlayer> players)
        : this(hand, date)
    {
        this.players = players;
    }

    public void AddPlayer(IPlayer player)
    {
        players.Add(player);
    }

    public void ProcessInformation()
    {
        Console.WriteLine(ToString());
    }

    public override string ToString()
    {
        StringBuilder info = new StringBuilder("Hand #: " + hand + " Date: " + date.ToLongDateString());
        info.Append("\nPlayers:");
        foreach (var s in players)
        {
            info.Append("\n"); 
            info.Append(s.Name);
        }
        return info.ToString();
    }
}

public class MySampleProvider1 : IDataProvider
{
    public IOnlinePokerInfo ParseFileInformation(FileInfo input)
    {
        MyOnlinePokerInfo info = new MyOnlinePokerInfo(1, DateTime.Now);
        IPlayer p = new MyPlayer("me");
        info.AddPlayer(p);
        return info;
    }
}

public class MySampleProvider2 : IDataProvider
{
    public IOnlinePokerInfo ParseFileInformation(FileInfo input)
    {
        MyOnlinePokerInfo info = new MyOnlinePokerInfo(2, DateTime.Now);
        IPlayer p = new MyPlayer("you");
        info.AddPlayer(p);
        return info;
    }
}

public class MyPlayer : IPlayer
{
    private string name;
    public string Name { get { return name; } set { name = value; } }

    public MyPlayer(string name)
    {
        this.name = name;
    }
}

public class OnlinePokerInfoManager
{
    static void Main(string[] args)
    {
        List<IOnlinePokerInfo> infos = new List<IOnlinePokerInfo>();

        MySampleProvider1 prov1 = new MySampleProvider1();
        infos.Add(prov1.ParseFileInformation(new FileInfo(@"c:\file1.txt")));

        MySampleProvider2 prov2 = new MySampleProvider2();
        infos.Add(prov2.ParseFileInformation(new FileInfo(@"c:\file2.log")));

        foreach (var m in infos)
        {
            m.ProcessInformation();
        }
    }
}
bruno conde
+3  A: 

This sounds like a candidate for the Strategy pattern. An example in C# can be found here and another one here. A brief description is available on Wikipedia.

More complete descriptions is available in book by Fowler and Kerievsky.

It is also available from the GoF book.

Mattias Holmqvist
A: 

Sounds like you need the Strategy pattern, which allows you to implement an algorithm in a number of different ways:

http://en.wikipedia.org/wiki/Strategy_pattern

George Jempty
A: 

You could also consider using the Command Pattern where you would have an Action for reach time of file type you need to process. This way you can have the flexibility for all the formats and adhere to the consistent parameters that your process will require.

Another benefit is that you can create new Actions for each new file format without refactoring the code for the other formats.

David Robbins