Search code examples
c#design-patternsbuilder-pattern

prevent object from instantiation in fluent builder pattern C#


i am trying to create fluent builder pattern to create user request as it has lot of parameters. for simplicity i am just showing few parameters

Here is my request class or the model

public class Request
    {
        public string UserName {  get; set; }

        public string Password {  get; set; }

        public string Token {  get; set; }


    }

Here is my builder class that build the requests.

 public class RequestBuilder
    {
        private string _username;
        private string _password;
        private string _token;

        public RequestBuilder UserName(string username)
        {
            _username = username;
            return this;

        }

        public RequestBuilder Password(string password)
        {
            _password = password;
            return this;

        }

        public RequestBuilder Token(string token)
        {
            _token = token;
            return this;

        }

        public static implicit operator Request(RequestBuilder requestBuilder)
        {

            return new Request()
            {

                UserName = requestBuilder._username,
                Password = requestBuilder._password,
                Token = requestBuilder._token

            };
        }
    }

At a glance this approach might look working but it has security holes like

  1. User can create Request direct using Request request = new Request()
  2. if i restric the request class by implementing the parameterized constructor in Request class

     public Request(RequestBuilder rb){                      
            UserName = rb._username;
            Password = rb._password;
            Token    = rb._token;                    
     }
    

In this case i need to create set and get method in RequestBuilder which will eventually expose RequestBuilder as follows

RequestBuilder rb = new RequestBuilder();
rb._username ="test";

so can anyone tell me how shall i protect Request class preventing from instantiation.


Solution

  • I tried to find the solution and end up with the following

    1. using Builder as nested class
    2. making Request class default constructor private. However, Builder is a nested class it can access request class and instantiate it
    3. In order to create the object of Request class user has to go through the Builder only.

    Request request = new Request.Builder().UserName("user").Password("abc").Build();

    Sample code

    public class Request
        {
            public string UserName {   get; private set; }
    
            public string Password {  get; private set; }
    
            public string Token { get; private set; }
    
    
            private Request(){
    
    
    
    
            }
    
            public class Builder
            {
    
                private Request request = new Request();
    
                public Builder UserName(string username)
                {
                    request.UserName = username;
                    return this;
    
                }
    
                public Builder Password(string password)
                {
                    request.Password = password;
                    return this;
    
                }
    
                public Builder Token(string token)
                {
                    request.Token = token;
                    return this;
    
                }
    
    
                public Request Build()
                {
    
                    return request;
                }
    
    
            }
        }