【问题标题】:How to modify the already built object in Java, when the Object is built using Builder Pattern?当使用 Builder Pattern 构建对象时,如何修改 Java 中已经构建的对象?
【发布时间】:2020-01-29 20:36:24
【问题描述】:

我已经(使用Builder 模式)构建了一个包含三个字段NameAgeGender 的Employee 对象。

public class Employee {

    private String name;
    private String age;
    private String gender;

    // Constructor
    private Employee(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.gender = builder.gender;
    }

    // Employee Builder
    public static class Builder {
        private String name;
        private String age;
        private String gender;

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder age(String age) {
            this.age = age;
            return this;
        }

        public Builder gender(String gender) {
            this.gender = gender;
            return this;
        }
    }

    // Getters
    public String getName() {
        return name;
    }

    public String getAge() {
        return age;
    }

    public String getGender() {
        return gender;
    }
}

现在我在下面的类中构建了我的 Employee 对象,

public class TestEmployee {

    public static void main(String[] args) throws IOException {
        Employee employee = new                Employee.Builder().age("23").gender("Male").name("John").build();

        System.out.println("Name : " + employee.getName());
        System.out.println("Age : " + employee.getAge());
        System.out.println("Gender : " + employee.getGender());
    }
}

如何通过破坏已构建的员工对象来修改员工“John”的年龄?

仅供参考:我不想在我的 Employee 对象中包含 Setters

【问题讨论】:

  • 反射是一种选择?
  • 不,他绝对不应该使用反射。
  • @Kayaman builder 用于创建不可变对象..当您说 builder 我信任您并假设它是不可变的..我看不到其他修改不可变对象的方法..
  • 创建不可变对象然后通过反射修改它们存在逻辑缺陷。仅仅因为你能做到并不意味着你应该这样做。如果要修改已创建的对象,请不要使其不可变。
  • 这是一个否定自己的问题。作者不明白他问的是什么。 IE:我怎么吃苹果,然后手里拿着同一个苹果?

标签: java object builder


【解决方案1】:

你想修改一个不可变对象。你看到那里的问题了吗?

要么添加设置器(或任何改变状态的方法),要么接受对象是不可变的。

您当然可以根据旧对象的值创建一个新对象,但它不会是同一个对象。

【讨论】:

  • 我同意你的看法。谢谢提供信息。现在我明白了。
【解决方案2】:

使用 Copy-On-Write 构建另一个(重复使用现有字段但更改年龄)。

Employee.Builder()
     .age(employee.getAge() + 1)
     .gender(employee.getGender())
     .name(employee.getName())
     .build();

记住,这将是另一个对象。

【讨论】:

    【解决方案3】:

    啊,我也试图用这种方法解决我的问题,具有讽刺意味的是,我偶然发现了这个问题。我理解这里的挑战,我们正在尝试使用相同的构建器设置器修改一个对象,但这样做我们最终会得到一个新对象。

    我发现有一个解决方案,所以大约 5 年后,这是我的答案 LOL(给最终会在这里的人)

    首先,不要在内部静态 Builder 类中创建 OuterClass 的重复属性。 *在Builder类中声明一个外部类的实例。这意味着您的 build() 方法将返回该实例。

    这个 *declaration of instance 是有意的,因为我计划在内部创建它或从外部请求它的内存。

    public class Employee {
    
        private String name;
        private String age;
        private String gender;
    
    
        public Static Builder builder()
        {
           return new Builder();
        }
    
        public Static Builder modifier(Employee employee)
        {
           return new Builder(employee);
        }
    
    
        // Employee Builder
        public static class Builder {
            private Employee employee;
    
            public Builder(Employee employee)
            {
               this.employee = employee;
            } 
    
            public Builder()
            {
               this.employee = new Employee();
            }
    
            public Builder name(String name) {
                this.employee.name = name;
                return this;
            }
    
            public Builder age(String age) {
                this.employee.age = age;
                return this;
            }
    
            public Builder gender(String gender) {
                this.gender = gender;
                return this;
            }
    
            public Employee build()
            {
               return this.employee;
            }
        }
    
        // Getters
        public String getName() {
            return name;
        }
    
        public String getAge() {
            return age;
        }
    
        public String getGender() {
            return gender;
        }
    }
    

    注意这里的调整,我引入了一个修改器,它接受 Employee 对象并进一步允许客户端使用 Builder 模式修改它。 所以你的客户会这样使用它......

    创建新员工

    Employee employee = Employee.builder().name("abc).age(20).build();
    

    修改同一个实例

    Employee.modifier(employee)
            .name("xyz")
            .build();
    

    【讨论】:

    • 这样没问题,但是我们不是在这里失去了对象不变性的关键属性吗?而且,既然我们允许他们修改现有对象..那么为什么不在对象本身中引入 setter 呢?
    【解决方案4】:

    如果您不想放置 setter(并使 Employee 可变),则不能修改 john 的年龄...而不是这个,您可以做的是:

    employee = new Employee.Builder()
                           .age("21")
                           .gender(employee.getGender())
                           .name(employee.getName())
                           .build();
    

    【讨论】:

      【解决方案5】:

      如果您不想要 setter 或公共非最终字段,那么您可以向构建器添加一个额外的构造函数,这将导致与实例匹配的初始状态,但构建器 setter 可用。这不会修改原始对象,而是基于它创建一个新对象。

      public static class Builder {
          private String name;
          private String age;
          private String gender;
      
          public Builder(Employee employee) {
              this.name = employee.getName();
              this.age = employee.getAge();
              this.gender = employee.getGender();
          }
      
          public Builder name(String name) {
              this.name = name;
              return this;
          }
      
          public Builder age(String age) {
              this.age = age;
              return this;
          }
      
          public Builder gender(String gender) {
              this.gender = gender;
              return this;
          }
      
          public Employee build() {
              return new Employee(this);
          }
      }
      

      然后您可以按以下方式使用它。

      Employee employee = new Employee.Builder().age("23").gender("Male").name("John").build();
      Employee employee2 = new Employee.Builder(employee).name("Jane").build();
      

      【讨论】:

        猜你喜欢
        • 2016-12-01
        • 2012-09-18
        • 2016-01-04
        • 2019-10-11
        • 1970-01-01
        • 1970-01-01
        • 2016-10-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多