Search code examples
design-patternsfactory-pattern

Does this warrant (or qualify) as Factory pattern?


I have a collection of strings that need to be parsed (using RegEx patterns) in the hopes of finding certain types of information. The "types" of information can be an email address or an ip address or a FQDN or whatever. The source string can have a single value (one email address), multiple values of the same type (for example, two ip addresses), a mix of values (an email address and an ip address), or nothing.

To represent a found pattern I have a single class that has properties for the type (email, ip, etc) and its value. Whatever method does the parsing should return a list of said class where the count can be zero, one, or more.

My question is does this type of scenario make sense for the Factory pattern? I cannot use a constructor where the string is passed in as a parameter since a constructor returns a single class instance.

I then though about the abstract Factory approach but form my reading Factories are designed to return different classes.

Then I read another StackOverflow question where somebody states that the static Create() method of the WebRequest class is a Factory pattern. So my thought is can I do that by passing in the source string?

Update: Based on this response (http://stackoverflow.com/a/4828511/240372) the factory pattern should be used when you have "distinct implementations of the same interface". So my requirements do not meet that criteria. So...I am a little lost on the best approach...

Edit: I think my example use of email address and ip address may add confusion with people thinking I am only dealing with "addresses". That is not the case. Let me add some pseudo code to help illustrate.

Class TypeClass
   Property Name As String
   Property Pattern As String
End Class

Class FoundValue
   Property TypeName As String
   Property Value As String
End Class

Dim possibleTypes as List(Of TypeClass)
possibleTypes.Add(New TypeClass() With {.Name = "Email", .Pattern = "some_regex_pattern" }
possibleTypes.Add(New TypeClass() With {.Name = "IPAddress", .Pattern = "some_regex_pattern" }
possibleTypes.Add(New TypeClass() With {.Name = "Date", .Pattern = "some_regex_pattern" }
possibleTypes.Add(New TypeClass() With {.Name = "Integer", .Pattern = "some_regex_pattern" }

Dim sourceStrings as List(Of String)
sourceStrings.Add("hello")
sourceStrings.Add("1.2.3.4")
sourceStrings.Add("someone@somewhere.com; who@what.com")
sourceStrings.Add("C:\Windows\notepad.exe 24 who@what.com")

For Each source in sourceStrings
    For Each type in possibleTypes
       ' compare type.pattern to source and return list of list of FoundTypes 
       '
       ' for example, the last source string would return:
       '  list containing
       '     New FoundValue() With { .TypeName = "Integer", .Value = "24" }
       '     New FoundValue() With { .TypeName = "Email", .Value = "who@what.com" }
       '
       '  whereas the second source would return
       '  list containing
       '     New FoundValue() With { .TypeName = "IPAddress", .Value = "1.2.3.4" }

Thank you.


Solution

  • I dont think so-

    It sounds to me like you want to make a common interface for reading different types of "Things" from your text. I'd create concrete classes for each different thing type implementing the interface below.

    public interface IThingReader
    {
        IEnumerable<Thing> ReadThing(string content);
    }
    

    This approach allows you to encapsulate the reading/parsing/construction a specific type of address into a single place. In your case you may build a class to house a collection of readers and union the result of all of them. eg:

    public class CompositeReader
    {
        IThingReader[] Readers;
    
        public CompositeReader(IThingReader[] readers)
        {
           Readers = readers;
        }
    
        public List<Thing> ParseText(string text)
        {
            List<Thing> allThings = new List<Thing>();
    
               foreach(IThingReader reader in Readers)
               {
                   IEnumerable<Thing> things = reader.ReadThing(text);
                   allThings.AddRange(things);
               }
    
            return allThings;
        }
    }
    

    The factory would be more useful if you had to determine which type of thing was in a string and return the appropriate result. eg:

    public class EmailAddress : Thing
    public class IpAddress : Thing
    public class Number : Thing
    
    public class ThingFactory
    {
        public Thing GetThing(string text)
        {
            if (IsEmailAddress(text))
            {
                return new EmailAddress(text);
            }
            else if (IsIpAddress(text))
            {
                int[] ipAddressParts = SplitIpAddressParts(text);
                return new IpAddress(ipAddressParts);
            }
            else
            {
                throw new UnrecognisedThingException(text);
            }
        } 
    }
    

    So the example above uses a factory to determine which distinct implementation of the Thing class (common interface) to create.