java构造函数处理缺少参数的问题

java构造函数处理缺少参数的问题,java,Java,我这里有个人详细信息的代码,无论给出多少个可能的参数,都应该初始化这个人,例如仅身高和年龄或工资和年龄 我发现很难为每一个参数组合声明一个构造函数,还有比这更好的解决方案吗 class person { public static final int defalut_salary=1000; public static final int default_age=20; public static final double default_height=6; pu

我这里有个人详细信息的代码,无论给出多少个可能的参数,都应该初始化这个人,例如仅身高和年龄或工资和年龄
我发现很难为每一个参数组合声明一个构造函数,还有比这更好的解决方案吗

class person {
    public static final int defalut_salary=1000;
    public static final int default_age=20;
    public static final double default_height=6;
    public static final String default_name="jack";

    protected int salary;
    protected int age;
    protected double height;
    protected String name;  

    person(){       
    }
}

我建议使用
Builder
模式:

public final class Person {
    private final int salary;
    private final int age;
    private final double height;
    private final String name;

    public Person(int salary, int age, double height, String name) {
        this.salary = salary;
        this.age = age;
        this.height = height;
        this.name = name;
    }

    // Getters or whatever you want

    public static class Builder {
        // Make each field default appropriately
        private int salary = 1000;
        private int age = 20;
        private double height = 6;
        private String name = "jack";

        public Builder setSalary(int salary) {
            this.salary = salary;
            return this;
        }

        // Ditto for other properties

        public Person build() {
            return new Person(salary, age, height, name);
        }
    }
}
用法:

Person person = new Person.Builder().setAge(25).setHeight(15).build();

您可以在
Person
构造函数中执行验证,如果您想使任何字段成为必填字段,可以在
Builder
构造函数中使用这些字段。

我建议使用
Builder
模式:

public final class Person {
    private final int salary;
    private final int age;
    private final double height;
    private final String name;

    public Person(int salary, int age, double height, String name) {
        this.salary = salary;
        this.age = age;
        this.height = height;
        this.name = name;
    }

    // Getters or whatever you want

    public static class Builder {
        // Make each field default appropriately
        private int salary = 1000;
        private int age = 20;
        private double height = 6;
        private String name = "jack";

        public Builder setSalary(int salary) {
            this.salary = salary;
            return this;
        }

        // Ditto for other properties

        public Person build() {
            return new Person(salary, age, height, name);
        }
    }
}
用法:

Person person = new Person.Builder().setAge(25).setHeight(15).build();

您可以在
Person
构造函数中执行验证,如果您想使任何字段成为必填字段,可以在
Builder
构造函数中使用这些字段。

您可以将构造函数定义为使用基元包装类(如java.lang.Integer或java.lang.Double)而不是基元。不同之处在于,这允许您传递
null
而不是值。然后,您可以检查它们是否为
null
。当它们为空时,将指定默认值。如果它们不是,则为它们赋值

public Person(Integer salary, Integer age, Double height, String name) {
    if (salary == null) this.salary = salary else this.salary = default_salary;
    if (age == null) this.age = age else this.age = default_age;
    //...
}
调用
新人(1200,空,5.3,空)的意思是“创建一个起薪1200、默认年龄、身高5.3、默认姓名的人”


另一种方法是使用Jon Skeet的答案中所示的方法。它不那么简洁,但更具可读性。

您可以定义构造函数来获取基本包装类(如java.lang.Integer或java.lang.Double),而不是基本包装类。不同之处在于,这允许您传递
null
而不是值。然后,您可以检查它们是否为
null
。当它们为空时,将指定默认值。如果它们不是,则为它们赋值

public Person(Integer salary, Integer age, Double height, String name) {
    if (salary == null) this.salary = salary else this.salary = default_salary;
    if (age == null) this.age = age else this.age = default_age;
    //...
}
调用
新人(1200,空,5.3,空)的意思是“创建一个起薪1200、默认年龄、身高5.3、默认姓名的人”


另一种方法是使用Jon Skeet的答案中所示的方法。它不那么简洁,但更具可读性。

初始化默认构造函数中的所有字段,并使用方法设置所需字段中的值,例如:

class A{
    Field a;
    Field b;
    Field c;

    public A(){
        a = SOME_VALUE;
        b = SOME_VALUE;
        c = SOME_VALUE;
    }

    public A withA(Field a){ this.a = a; return this; }
    public A withB(Field b){ this.b = b; return this; }
    public A withC(Field c){ this.c = c; return this; }

    /* other code */
}
A a = new A().withB(SOME_OTHER_VALUE).withC(YET_DIFFERENT_VALUE);
然后你可以这样使用它:

class A{
    Field a;
    Field b;
    Field c;

    public A(){
        a = SOME_VALUE;
        b = SOME_VALUE;
        c = SOME_VALUE;
    }

    public A withA(Field a){ this.a = a; return this; }
    public A withB(Field b){ this.b = b; return this; }
    public A withC(Field c){ this.c = c; return this; }

    /* other code */
}
A a = new A().withB(SOME_OTHER_VALUE).withC(YET_DIFFERENT_VALUE);

如果不希望在后续调用
withX()
方法时更改字段的值,可以使用成熟的构建器模式。

初始化默认构造函数中的所有字段,并使用方法设置所需字段中的值,例如:

class A{
    Field a;
    Field b;
    Field c;

    public A(){
        a = SOME_VALUE;
        b = SOME_VALUE;
        c = SOME_VALUE;
    }

    public A withA(Field a){ this.a = a; return this; }
    public A withB(Field b){ this.b = b; return this; }
    public A withC(Field c){ this.c = c; return this; }

    /* other code */
}
A a = new A().withB(SOME_OTHER_VALUE).withC(YET_DIFFERENT_VALUE);
然后你可以这样使用它:

class A{
    Field a;
    Field b;
    Field c;

    public A(){
        a = SOME_VALUE;
        b = SOME_VALUE;
        c = SOME_VALUE;
    }

    public A withA(Field a){ this.a = a; return this; }
    public A withB(Field b){ this.b = b; return this; }
    public A withC(Field c){ this.c = c; return this; }

    /* other code */
}
A a = new A().withB(SOME_OTHER_VALUE).withC(YET_DIFFERENT_VALUE);


如果不想在后续调用
withX()
方法时更改字段的值,可以使用成熟的构建器模式。

构建器模式可以解决您的问题。您可以使用映射作为参数,然后只需要一个构造函数。Groovy就是这样实现命名参数的。@assylias谢谢你,这很有用,非常有用。顺便问一下,这与性能有什么关系?生成器模式可以解决你的问题。你可以使用映射作为参数,然后只需要一个构造函数。Groovy就是这样实现命名参数的。@assylias谢谢你,这很有用,非常有用。顺便问一下,这与性能有什么关系?使用生成器模式而不是像我建议的那样灵活的构造函数需要在实现和使用它的代码中都有更详细的代码。但优点是调用更具可读性。当一个构造函数包含多个参数时,很难判断哪个参数起什么作用,但使用生成器模式,很明显生成器的哪个方法设置了什么属性。@Christian:代码已经有效,我希望它是什么样的-
builder
类是
Person
中的嵌套类。有了您的更改,底部的用法将无效。根据我的经验,在类型本身中嵌套一个类型的生成器是相当常见的。感谢您在那里纠正我并回滚我的更改!现在我仔细看了看,我也看到了我的错误!使用构建器模式而不是像我建议的那样灵活的构造函数,需要在实现和使用它的代码中使用更详细的代码。但优点是调用更具可读性。当一个构造函数包含多个参数时,很难判断哪个参数起什么作用,但使用生成器模式,很明显生成器的哪个方法设置了什么属性。@Christian:代码已经有效,我希望它是什么样的-
builder
类是
Person
中的嵌套类。有了您的更改,底部的用法将无效。根据我的经验,在类型本身中嵌套一个类型的生成器是相当常见的。感谢您在那里纠正我并回滚我的更改!现在我仔细看了看,我也看到了我的错误!你的“if-else”漏了一个分号,感觉不像Java(这里
?:
既短又清晰)。@maaartinus我故意避免使用三元运算符,因为OP显然没有经验,没有经验的开发人员经常会被它弄糊涂。你的“if-else”漏了一个分号,感觉不像Java(此处
?:
既简短又清晰)@maaartinus我故意避免使用三元运算符,因为OP显然没有经验,没有经验的开发人员经常会被它弄糊涂。请注意,许多人希望
withX
像does一样创建一个新对象。我会选择
setX
。请注意,许多人希望
withX
像does一样创建一个新对象。我希望转到
setX