The Josh Bloch Builder Pattern (here after JBBuilder) introduced me to the idea of using a nested class to aid in construction. In Java the JBBuilder pattern is aimed at fixing the telescoping constructor problem. That problem occurs in java mostly because java doesn't have named and optional arguments the way C# does. Because the C# has them I'm wondering how good an idea the JBBuilder is in C#. I'm trying to solve a different problem with a structure similar to the JBBuilder.
I will also use a nested class to build. But rather than following the JBBuilder pattern and simulating optional arguments I'll use the nested class to let me simulate constructors with different names.
These simulated constructors will be much like static factory methods but without them being static. I'm avoiding static factory methods because they can't be passed around dependency injection style. I want whatever decides which method to call to not have to know which concrete method this is. So I'm hanging them off a stateless instance that could have any implementation.
These simulated constructors will give an input string different meanings and choose an implementation of a Strategy Pattern to wrap that string with different Validate()
behavior.
Using differently named 'constructors' allows us to deal with the fact that input in both cases is the same type: string. One is a regular expression. The other is wildcard pattern. The meaning of the string is decided by the method used from the Build object.
The different names avoid a single constructor being forced to do logic or accept a flag to understand the strings meaning and select an implementation or choosing a constructor based on the type passed in. The new pattern presented below is a hack that allows constructors to have different names without resorting to static factory methods. It gives the string different types that then polymorphically decide the Validate()
behavior.
My questions:
- Is the new pattern needed in c#? If not, what makes it unnecessary?
- Does the nested builder class have a name when used to allow non-static constructors different names? It's structurally similar to the Josh Bloch Builder but the motivation here is different.
The Strategy Pattern used by the new pattern:
public interface IValidationStrategy
{
bool Validate(string pStringToValidate);
}
public class RegexValidator : IValidationStrategy
{
private Regex regEx;
public RegexValidator(Regex regEx)
{
this.regEx = regEx;
}
public bool Validate(string stringToValidate)
{
return regEx.IsMatch(stringToValidate);
}
}
public class WildCardValidator : IValidationStrategy
{
private string wildCard;
public WildCardValidator(string wildCard)
{
this.wildCard = wildCard;
}
public bool Validate(string pStringToValidate)
{
//http://stackoverflow.com/questions/30299671/matching-strings-with-wildcard
string regex = Regex.Escape(wildCard).Replace("\\*", ".*");
return Regex.IsMatch(pStringToValidate, "^" + regex + "$");
}
}
The new pattern:
Accepts a Dependency Injection (IValidationStrategy) and using a nested builder class to construct the different implementations in an immutable way. The method used decides the input string is interpreted, as a wildcard or a regular expression.
public class StringValidator
{
private IValidationStrategy validationStrategy;
//Dependendency Injection constructor
public StringValidator(IValidationStrategy validationStrategy)
{
this.validationStrategy = validationStrategy;
}
public bool Validate(string stringToValidate)
{
return validationStrategy.Validate(stringToValidate);
}
public class Builder
{
public StringValidator Regex(string regex)
{
return new StringValidator(new RegexValidator(new Regex(regex)));
}
public StringValidator WildCard(string wildCard)
{
return new StringValidator(new WildCardValidator(wildCard));
}
}
}
Two different ways to test:
class Program
{
static void Main(string[] args)
{
Console.Out.WriteLine(
"IsValid: {0}",
new StringValidator.Builder()
.Regex(@"\d+")
.Validate("55")
);
Console.Out.WriteLine(
"IsValid: {0}",
new StringValidator.Builder()
.WildCard("*")
.Validate("Whatever string to be validated")
);
// Or, if you hate using nameless temporary objects
Console.Out.WriteLine();
StringValidator.Builder stringValidatorBuilder = new StringValidator.Builder();
string regex = @"\d+";
StringValidator regValidator = stringValidatorBuilder.Regex(regex);
bool isValid = regValidator.Validate("55");
Console.Out.WriteLine("IsValid: {0}", isValid);
string wildCard = "*";
StringValidator wildCardValidator = stringValidatorBuilder.WildCard(wildCard);
isValid = wildCardValidator.Validate("Whatever string to be validated");
Console.Out.WriteLine("IsValid: {0}", isValid);
}
}
Outputs:
IsValid: True IsValid: True IsValid: True IsValid: True
This code is from a Software Engineering Stack Exchange answer by Vladimir Stokic that I've made some improvement's to with his kind permission. You can explore the original form, that had no builder, in the edit history if you wish.
The responses are surprising me with how fixated they are on explaining how to properly use the builder pattern. I see no reason every use of a inner class must conform to the Josh Bloch Builder Pattern. I mentioned it mostly to show how that patterns usefulness in C# is limited compared to in Java. Perhaps a different example solution will help.
If I didn't mind using static factory methods (I do, they can't be passed around nicely) I'd solve the problem of constructors needing different names more simply:
public class StringValidatorStatic
{
private IValidationStrategy validationStrategy;
//Dependendency Injection constructor
public StringValidatorStatic(IValidationStrategy validationStrategy)
{
this.validationStrategy = validationStrategy;
}
public static StringValidatorStatic Regex(string regex)
{
return new StringValidatorStatic(new RegexValidator(new Regex(regex)));
}
public static StringValidatorStatic WildCard(string wildCard)
{
return new StringValidatorStatic(new WildCardValidator(wildCard));
}
public bool Validate(string stringToValidate)
{
return validationStrategy.Validate(stringToValidate);
}
}
And use it this way:
static void Main(string[] args)
{
Console.Out.WriteLine(
"IsValid: {0}",
StringValidatorStatic
.Regex(@"\d+")
.Validate("55")
);
Console.Out.WriteLine(
"IsValid: {0}",
StringValidatorStatic
.WildCard("*")
.Validate("Whatever string to be validated")
);
}
This works fine. Usage isn't more complicated. But now I'm stuck referring to this statically. I want my version of the builder to be something that can be passed around as a reference.
StringValidator.Builder().Regex(@"\d+")
toStringValidator.Builder().WildCard("*")
everywhere? That's no better than changing which concrete class you instantiate. It's likely that I'm misunderstanding the question, but I'm just not at all clear what exactly you are and aren't trying to solve. And moreover why a builder has anything to do with it rather than a factory. \$\endgroup\$Wildcard()
rather thanRegex()
indicates a different meaning for the string passed in. Changing fromStringValidator
to something else indicates that a different implementation should be doing the work of turning that string into whichever meaning it's meant to have. That's something you don't get to do if you use static factory methods or constructors. You do get it if the code that uses wildcards and regex accepts an injection ofIStringValidatorBuilder
. \$\endgroup\$