3
\$\begingroup\$

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:

  1. Is the new pattern needed in c#? If not, what makes it unnecessary?
  2. 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.

\$\endgroup\$
4
  • \$\begingroup\$ " I want my version of the builder to be something that can be passed around as a reference." Why? You can't do this with constructors, which is apparently what you're trying to replace \$\endgroup\$ Nov 5, 2016 at 2:00
  • \$\begingroup\$ @BenAaronson if constructors could do everything I wanted them to do I wouldn't be trying to replace them. Say you wanted to produce the current time as a string. Say you wanted to use that in many places. Now say you want to change to a different time class to produce that string. Did you spread knowledge of the old concrete time class everywhere or did you keep it in one place? \$\endgroup\$ Nov 5, 2016 at 5:40
  • \$\begingroup\$ But wouldn't switching, in your builder example, mean switching from, e.g., StringValidator.Builder().Regex(@"\d+") to StringValidator.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\$ Nov 5, 2016 at 10:09
  • \$\begingroup\$ @BenAaronson choosing to use Wildcard() rather than Regex() indicates a different meaning for the string passed in. Changing from StringValidator 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 of IStringValidatorBuilder. \$\endgroup\$ Nov 5, 2016 at 11:05

4 Answers 4

3
+50
\$\begingroup\$

Why create a class to wrap the validation strategy at all? A common pattern with immutable objects is to have an empty or seed value to start construction from.

public interface IValidationStrategy
{
    bool Validate(string pStringToValidate);
}

public class RegexValidationStrategy : IValidationStrategy
{
    private Regex regEx;

    public RegexValidationStrategy(Regex regEx)
    {
        this.regEx = regEx;
    }

    public bool Validate(string stringToValidate)
    {
        return regEx.IsMatch(stringToValidate);
    }
}

public class StringValidator
{
    private class EmptyValidator : IValidationStrategy
    {
        public bool Validate(string input) => true;
    }

    public static readonly IValidationStrategy Empty = new EmptyValidator();
}

public static class RegexValidationStrategyExtensions
{
    public static IValidationStrategy Regex(this IValidationStrategy strategy, string pattern)
    {
        return new CompositeValidationStrategy(strategy, new RegexValidationStrategy(new Regex(pattern)));
    }
}

public class CompositeValidationStrategy : IValidationStrategy
{
    private readonly IValidationStrategy left;
    private readonly IValidationStrategy right;

    public CompositeValidationStrategy(IValidationStrategy left, IValidationStrategy right)
    {
        this.left = left;
        this.right = right;
    }

    public bool Validate(string input)
    {
        return left.Validate(input) && right.Validate(input);
    }
}

Then your test:

StringValidator
    .Empty
    .Regex(@"^\d+$")
    .Validate("55") // true

You can also apply more than 1 rule:

 StringValidator
    .Empty
    .Regex(@"^\d+$")
    .Regex("5{2,}")
    .Validate("1255") // true

By having separate classes and using extension methods to construct instances, you make it trivially easy to add more validators - create a type that implements the strategy and add an extension method to instantiate the type. You could add additional extension methods to IValidationStrategy to make composition easier and avoid leaking the knowledge of CompositeValidationStrategy.

\$\endgroup\$
2
  • \$\begingroup\$ I completely forgot about the composition pattern in this question. A nice try, but I doubt even this can satisfy the OP :-) \$\endgroup\$
    – t3chb0t
    Oct 31, 2016 at 16:19
  • \$\begingroup\$ I like the idea of the empty instance and multiple rules. Just wish you weren't tieing the usage to a concrete implementation by finding it statically. \$\endgroup\$ Nov 5, 2016 at 11:22
2
\$\begingroup\$

Aid in construction

I want to go back what's the intention of the pattern. I will try to address when you really get a benefit ("aid in construction") from this pattern so the pattern is not an alibi pattern.

The straightforward way to construct an object is to call the constructor. If you have a complex object, you may have a lot arguments to pass into construction.

Now the first problem comes with optional arguments. They will mostly lead to the "telescoping constructor problem". Named and optional arguments are technical answers to avoid multiple constructors that may call each other.

But multiple constructor are not the real problem. The real problem is that at some point of time you find yourself in trouble by finding a proper DEFAULT-Value for mandatory arguments. This may lead to another constructor that will call an existing constructor with the DEFAULT-Value.

So you have to distinguish between optional arguments and mandatory arguments that shall get a default.

The builder pattern (properly applied) will construct you a consistent object, even you haven't specified ANY argument.

AnyObject anyObject = new AnyObjectBuilder().build();

So the builder pattern should do following for you:

  • There should be no need to think about default values
  • There should be no need to think about argument order
  • The builder will keep its internal state consistent (due to constraints) so you can build a consistent object at ANY time
  • The builder holds the consistent state until YOU decide to build the object

Of course you can throw exceptions if an argument passed in would lead to an inconsistent state. I prefer the fail-safe variant of builders most of the time -> ignoring wrong input, adapt the input to the best consistent alternative or adapt internal state to fit the input.

If you do not implement the builder pattern like this, you have nothing more than another representation of the same structure. Maybe you can arrange your source code in another way (that seems to be more readable, but readability is subjective). But you should think about introducing a new class only for better formatting.

Nested class

Now to the point that the builder should be a "nested class". It doesn't matter WHO says this but it matters WHAT he/she wanted to address. But that something that is always part of the developers life: We want to keep things as isolated as possible (things that do not belong together should be separated) with maximum cohesion (things that belong together should be tied together).

As the constructor itself is part of the target class, the builder class itself should be located as near as possible to the constructor. As only the Builder class is necessary to exposed you can make your constructor(s) private. But as I said: The real benefit you will get if you take the burden of thinking about argument order, default values, consistency and build time.

Is this needed in c#? If not, what makes it unnecessary?

To answer this question is to compare the assertions the builder pattern gives you to the assertions named and optional parameters in C# give you.

  • "default values" -> check
  • "argument order" -> irrelevant because of names, check
  • "internal consistency" -> your approach has no need to address that, no state within builder
  • "construction delay" -> your approach does not address that, immediately construction

So if you don't want to delay object construction or you do not manage an internal state within your builder, you can use C# capabilities to achieve the first two assertions. As soon as the other aspects become important you should follow the standard pattern.

BTW: Your approach seems to use usual factory methods than any other pattern. And I don't know why anybody would insist on them to be "static".

Does the nested builder class have a name when used to allow non-static constructors different names?

Here I do not really know what you mean, but I will have a try: Names do not have meanings, they have usages. So names are not an issue as long as you share the same understanding of them with those who will also maintain the code. I think "Builder" is a quite good approximation to that what I think what you mean.

Another approach

In Java 8 you can use method references:

public class Main {


    public static class Factory {

        public static Factory get() {
            return new Factory();
        }

        public Function<String, Boolean> regex(String regex) {
            return x -> Pattern.compile(regex).matcher(x).matches();
        }

        public Function<String, Boolean> wildcard(String wildcard) {
            return x -> Pattern.compile("^" + wildcard.replace("\\*", ".*") + "$").matcher(x).matches();
        }

    }


    public static void main(String[] args) {

        // can be passed around
        Factory factory = Factory.get();

        // can be passed around
        Function<String, Boolean> regex = factory.regex("\\d+");

        System.out.println(regex.apply("55"));

        // can be passed around
        Function<String, Boolean> wildcard = factory.wildcard("*");

        System.out.println(wildcard.apply("Whatever string to be validated"));

    }


}

I think in C# you have similar possibilities described here.

\$\endgroup\$
5
  • \$\begingroup\$ I agree with all of this. I am however disappointed that none of it answers the question about the DIFFERENT pattern I'm presenting here. This reads like you only read the title of the question and not the body. I'm not asking how the typical Josh Bloch builder works or what it's supposed to do. I'm pointing out how the Josh Bloch builder is less useful in C# than in Java. I'm asking, in the context of C#, when needing to differentiate between input strings meant to be taken differently, is this code useful or is there a better way? Particularly because I'm trying to do it in C#. \$\endgroup\$ Oct 29, 2016 at 14:37
  • \$\begingroup\$ First of all I am glad to hear that at least someone is in fully aggreement with me about SOME things this week... ;-). \$\endgroup\$
    – oopexpert
    Oct 29, 2016 at 16:36
  • \$\begingroup\$ I think I could agree on the builder presented here being more like a factory than a builder. \$\endgroup\$
    – t3chb0t
    Oct 29, 2016 at 17:16
  • \$\begingroup\$ It's very much like a static factory. It just isn't static. Instead the methods hang off a stateless instance that can be passed around like any other dependency injection. What accepts the instance would control what methods are called. The instance would control what those methods do and what they return. You can't do that with static factory methods. \$\endgroup\$ Oct 29, 2016 at 18:31
  • \$\begingroup\$ Even if this question lies for a while I'd like to make a notice to design patterns: Design patterns are not made up. They were identified based on the structural neccessities from real world use cases. The following question arises: Where do you derive your pattern from? \$\endgroup\$
    – oopexpert
    Feb 4, 2017 at 12:47
1
\$\begingroup\$

Let me try again...


Here I'm also using a nested class to build.

I'm asking my self why. It doesn't have any advantage in your example (that it's nested).

But rather than following the pattern and simulating optional arguments I'm using it to choose an implementation of a Strategy Pattern.

A pattern that suggests using optional arguments instead of implementing a Strategy Pattern doesn't look like a real pattern, rather a bad advice from a lazy programmer.

Even the telescopic constructor problem does not introduce optional arguments. It just uses default values. They are still required to construct the object.

Implementing the Strategy Pattern in your case was the only right choice.

This avoids a constructor having to do logic to select an implementation or choosing a constructor based on the type passed in.

This is exactly why the strategy pattern was the right choice.

This is basically a hack that allows constructors to have different names without resorting to static factory methods.

No, this is not a hack. It's good SOLID design and that follows the OCP (Open Closed Principle) because you can add more strategies (open for extension) without modifying the class that uses them (closed for modification).

  1. Is this needed in c#? If not, what makes it unnecessary?

I'm not sure what you mean by is this needed? The strategy pattern or the nested builder? They have both they purposes. You used the strategy pattern correctly but the nested builder doesn't have to be nested. As I've already said in my previous answer, it only makes sense to nest it when you want to access private fields of the constructed objects becasue it's the only way to do this.

  1. 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.

Not that I'm aware of. Once again. Where you put the builder doesn't matter. As long as you don't set anything private of the constructed object it can be anywere and it will still work.

As a matter of fact you don't need the builder at all. You can create the object without it but we use a builder to make the creation of an object easier or by providing a fluent API and guiding the user step by step how to create an object but it's not necessary.

Whether you do:

new StringValidator.Builder().Regex(@"\d+").Validate("55")

or

new StringValidator(new RegexValidator(new Regex(regex))).Validate("55")

it will still produce the same result but it's simply easier (should be) to do it via the builder. There is no pattern that enforces it. You write one (builder) because you want shorter, more natural code.

The responses are surprising me with how fixated they are on explaining how to properly use the builder pattern.

Yes, because it seems that you think that you must use a builder because it's some kind of a cool pattern for everything. No it isn't. Strategy Pattern is cool. Builder makes things simpler.

I see no reason every use of a inner class must conform to the Josh Bloch Builder Pattern.

Inner classes are bad anyway. They should be usually avoid but a nested builder accessing private members is an exception. If it doesn't then it shouldn't be nested.

Your builder shouldn't actaully be nested. It should be outside the class and be called StringValidatorBuilder. It wouldn't change anything how it works.


The missing feature would be allowing constructors with different names

Then I guess you shouldn't have gone with the Strategy Pattern but with inheritance. This would allow you to define types with different names and craete them from different names too. (I wouldn't in this case).

\$\endgroup\$
1
  • \$\begingroup\$ Comments are not for extended discussion; this conversation has been moved to chat. \$\endgroup\$
    – janos
    Oct 29, 2016 at 18:15
1
\$\begingroup\$

My personal conclusion is that, based on your sample program, StringValidator does not have any value.

Let's see why:

new StringValidator.Builder()
    .Regex(@"\d+")
    .Validate("55")

Sure you can use one Regex validator. But let's try to use many of them:

new StringValidator.Builder()
    .Regex(@"[ABC]\d+")
    .Regex(@"\d+")
    .Validate("55")

It doesn't even compile! If you are making a builder that supports multiple validations, there should at least exist one way of specifying those validations. In your code there isn't such a way.

And if this code would compile, you guessed it. The "validator" will only validate according to the last Regex, and the string 55 will be valid, resulting on a confusing behavior for the client of the code.

I was way better off if I could simply create as many instances of RegexValidator as I like and use them in the right way:

var validators = new IValidationStrategy[]{
    new RegexValidator(new Regex("[ABC]\d+")),
    new RegexValidator(new Regex("[\d+")),
}
var isValid = validators.All(v => v.Validate("55"));

What you might argue is that RegexValidator is missing a construtor with a string

public RegexValidator(string regex){
    regEx = new Regex(regex);
}
\$\endgroup\$
2
  • \$\begingroup\$ YAGNI \$\endgroup\$ Oct 31, 2016 at 10:35
  • 1
    \$\begingroup\$ +1 The StringValidator class is exactly the IValidationStrategy interface repeated. StringValidator.Builder.Regex == RegexStrategy, StringValidator.Builder.Wildcard == WildcardStrategy \$\endgroup\$
    – Caleth
    Oct 31, 2016 at 11:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.