How many constructor arguments is too many?

前端 未结 15 1185
[愿得一人]
[愿得一人] 2020-11-29 15:03

Let\'s say you have a class called Customer, which contains the following fields:

  • UserName
  • Email
  • First Name
  • Last Name

相关标签:
15条回答
  • 2020-11-29 15:34

    I think it all depends on the situation. For something like your example, a customer class, I wouldn't risk the chance of having that data being undefined when needed. On the flip side, passing a struct would clear up the argument list, but you would still have a lot of things to define in the struct.

    0 讨论(0)
  • 2020-11-29 15:36

    Style counts for a lot, and it seems to me that if there is a constructor with 20+ arguments, then the design should be altered. Provide reasonable defaults.

    0 讨论(0)
  • 2020-11-29 15:39

    In a more Object-Oriented situation of the problem, you can use properties in C#. It doesn't help much if you create an instance of an object, but suppose we have a parent class that needs too many parameters in its constructor.
    Since you can have abstract properties, you can use this to your advantage. The parent class needs to define an abstract property that the child class must override.
    Normally a class might look like:

    class Customer {
        private string name;
        private int age;
        private string email;
    
        Customer(string name, int age, string email) {
            this.name = name;
            this.age = age;
            this.email = email;
        }
    }
    
    class John : Customer {
        John() : base("John", 20, "John@email.com") { 
    
        }
    }
    

    It can become messy and unreadable with too many parameters.
    Whereas this method:

    class Customer {
        protected abstract string name { get; }
        protected abstract int age { get; }
        protected abstract string email { get; }
    }
    
    class John : Customer {
        protected override string name => "John";
        protected override int age => 20;
        protected override string email=> "John@email.com";
    }
    

    Which is much cleaner code in my opinion and no contractors are needed in this case, which saves room for other necessary parameters.

    0 讨论(0)
  • 2020-11-29 15:41

    If you have unpalatably many arguments, then just package them together into structs / POD classes, preferably declared as inner classes of the class you are constructing. That way you can still require the fields while making the code that calls the constructor reasonably readable.

    0 讨论(0)
  • 2020-11-29 15:42

    Two design approaches to consider

    The essence pattern

    The fluent interface pattern

    These are both similar in intent, in that we slowly build up an intermediate object, and then create our target object in a single step.

    An example of the fluent interface in action would be:

    public class CustomerBuilder {
        String surname;
        String firstName;
        String ssn;
        public static CustomerBuilder customer() {
            return new CustomerBuilder();
        }
        public CustomerBuilder withSurname(String surname) {
            this.surname = surname; 
            return this; 
        }
        public CustomerBuilder withFirstName(String firstName) {
            this.firstName = firstName;
            return this; 
        }
        public CustomerBuilder withSsn(String ssn) {
            this.ssn = ssn; 
            return this; 
        }
        // client doesn't get to instantiate Customer directly
        public Customer build() {
            return new Customer(this);            
        }
    }
    
    public class Customer {
        private final String firstName;
        private final String surname;
        private final String ssn;
    
        Customer(CustomerBuilder builder) {
            if (builder.firstName == null) throw new NullPointerException("firstName");
            if (builder.surname == null) throw new NullPointerException("surname");
            if (builder.ssn == null) throw new NullPointerException("ssn");
            this.firstName = builder.firstName;
            this.surname = builder.surname;
            this.ssn = builder.ssn;
        }
    
        public String getFirstName() { return firstName;  }
        public String getSurname() { return surname; }
        public String getSsn() { return ssn; }    
    }
    
    import static com.acme.CustomerBuilder.customer;
    
    public class Client {
        public void doSomething() {
            Customer customer = customer()
                .withSurname("Smith")
                .withFirstName("Fred")
                .withSsn("123XS1")
                .build();
        }
    }
    
    0 讨论(0)
  • 2020-11-29 15:42

    I agree on the 7 item limit Boojiboy mentions. Beyond that, it may be worth looking at anonymous (or specialized) types, IDictionary, or indirection via primary key to another data source.

    0 讨论(0)
提交回复
热议问题