Abstract Factory + Strategy pattern for parsing log files in multiple formats — improvement suggestions? I'm writing a service to parse machine log files as they are written to a central directory and push them to a web service. Each machine generates several log files at a time, with each file encapsulating a particular domain of operational information (e.g. user login sessions, errors, statistics, etc.).

The log files are written by different models of machines from different manufacturers. All the machines generate the same kinds of information, but the structure of the log files differs according to the manufacturer of the machine and the type of information the log file contains. Below is a sketch of a set of factories that will create Log classes for each type of log file and configure them with a Parser appropriate for that manufacturer (Strategy Pattern). 

Over time new machines will be added to the logging pool and it should be straightforward to add support for these. The proposed design is arranged around the manufacturer and it makes it simple to add support for new manufacturers. However, I am concerned about a scenario in which a new model from an existing manufacturer does not adhere to that manufacturer's existing log format. 

Is there a better design?

public interface ILogFactory
{
    ISessionLog CreateSessionLog();
    ITipLog CreateTipLog();
    IStatisticsLog CreateStatisticsLog();
}

public class SmithsLogFactory : ILogFactory
{
    public ISessionLog CreateSessionLog()
    {
        return new SessionLog() { Parser = new SmithsSessionStrategy(); }
    }

    public ITipLog CreateTipLog()
    {
        return new TipLog() { Parser = new SmithsTipStrategy(); }
    }

    public IStatisticsLog CreateStatisticsLog()
    {
        return new StatisticsLog() { Parser = new SmithsStatsStrategy(); }
    }
}

public class L3LogFactory : ILogFactory
{
    public ISessionLog CreateSessionLog()
    {
        return new SessionLog() { Parser = new L3SessionStrategy(); }
    }

    public ITipLog CreateTipLog()
    {
        return new TipLog() { Parser = new L3TipStrategy(); }
    }

    public IStatisticsLog CreateStatisticsLog()
    {
        return new StatisticsLog() { Parser = new L3StatsStrategy(); }
    }
}

public class VividFactory : ILogFactory
{
    public ISessionLog CreateSessionLog()
    {
        return new SessionLog() { Parser = new VividSessionStrategy(); }
    }

    public ITipLog CreateTipLog()
    {
        return new TipLog() { Parser = new VividTipStrategy(); }
    }

    public IStatisticsLog CreateStatisticsLog()
    {
        return new StatisticsLog() { Parser = new VividStatsStrategy(); }
    }
}
Few thoughts about your code:


your case resembles more Abstract Factory pattern more than Strategy pattern. ILogFactory is your Abstract Factory while SmithsLogFactory, VividFactory etc are yours Concrete Factories. ISessionLog, ITipLog and IStatisticsLog are Abstract Products and, for example, TipLog with L3TipStrategy inside is your Product.
Because I see this case as Abstract Factory, I would add derived versions of ISessionLog, ITipLog and IStatisticsLog for each manufacturer. Constructor of each of those classes should take care of details - like creating proper version of Parser subclass. 
When using Abstract Factory I always like to provide * construction parameters* to the methods, which can be used to control concrete products creation - and here is the place where I would handle issue with different versions of the logs from the same manufacturer.


Draft summarizing my thoughts:

    public class LogFactoryParameters
    {
       // ... for example, Version
    }

    public class L3LogFactory : ILogFactory
    {
        public ISessionLog CreateSessionLog(LogFactoryParameters parameters)
        {
            return new L3SessionLog(parameters);
        }

        public ITipLog CreateTipLog(LogFactoryParameters parameters)
        {
           return new L3TipLog(parameters);
        }

        public IStatisticsLog CreateStatisticsLog(LogFactoryParameters parameters)
        {
           return new L3StatisticsLog(parameters);
        }
    }