当我们可以用 setter 做同样的事情时,为啥我们需要使用 builder 设计模式? [复制]

Posted

技术标签:

【中文标题】当我们可以用 setter 做同样的事情时,为啥我们需要使用 builder 设计模式? [复制]【英文标题】:Why do we need to use the builder design pattern when we can do the same thing with setters? [duplicate]当我们可以用 setter 做同样的事情时,为什么我们需要使用 builder 设计模式? [复制] 【发布时间】:2019-09-08 22:56:04 【问题描述】:
public class Employee 
    private String name;
    private String address;
    private int id;

    public Employee() 
        // TODO Auto-generated constructor stub
    

    @Override
    public String toString() 
        return "Employee [name=" + name + ", address=" + address + ", id=" + id + "]";
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public String getAddress() 
        return address;
    

    public void setAddress(String address) 
        this.address = address;
    

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    



public class Main  
    public static void main(String[] args) 
        Employee e = new Employee();
        e.setName("Priyanka");
        Employee e1 = new Employee();
        e1.setName("Rahul");
        e1.setAddress("Delhi");
        System.out.println("Value of e :"+ e);
        System.out.println("Value of e1:"+ e1);
    

【问题讨论】:

Setter 并不能保证你得到的物品是有效的。他们不能。建设者可以。假设您忘记调用employee.setId(),那么您将获得一个属性为空值的对象。而如果你这样做employeeBuilder.build(),你可能会得到一个异常,或者可能只是自动将 ID 设置为下一个可用的 - 不应该在 Employee 对象中的逻辑。 【参考方案1】:

构建器模式可用于:

对用于初始化对象的数据进行一些检查。例如,如果您需要在变量之间进行双重检查 创建不可变对象。初始化后无法更改对象,因此无法使用设置器 增加代码的可读性。 减少用于初始化对象的代码 使实例处于有效状态。使用 setter,在调用所有 setter 之前,对象实例可能处于无效状态。

关于使用构建器创建不可变对象的注意事项。

当您在多线程环境中工作时,可以在线程之间共享不可变对象而无需显式同步。因为对象在这段时间内不能改变,所以不可能有竞争条件同时被两个线程访问和修改。

【讨论】:

另外,它使您不需要临时变量【参考方案2】:

没有必要使用 any 模式。您甚至可以通过公开变量来避免设置器。然而,

Builder 设计模式的目的是将 从表示构造复杂对象

来源:https://en.wikipedia.org/wiki/Builder_pattern

【讨论】:

... 这更易于使用,因为大多数 Builder 的方法返回对 this 的引用以允许调用链接。可以写:Employee jonSkeet = new Employee.Builder().withName("Jon").withLastname("Skeet").withSalary(1_000_000).build() @spi 它使代码更易于阅读和调试。这是使用构建器设计模式的唯一原因吗? @PriyankaTaneja 是唯一一个没有...您还可以构建多个“Jon Skeet”,只需多次调用build()。同样,这似乎是一个次要的优势,但这些小东西放在一起会在简单代码和意大利面条代码之间产生很大的不同。 想象一下,你有一个带有 10 个参数的主构造函数(一开始是个坏主意),并且字段设置为默认值。您可以使用 Builder 设计模式来设置各种值而不会混淆,而不是使用多个构造函数来设置某些值,同时保留其他值的默认值。【参考方案3】:

使用构建器模式有几个优点:

    与设置器(使您的类可变)不同,构建器可用于构造不可变对象。在许多情况下,不可变对象比可变对象更受欢迎,因为它们更易于理解和维护,并且避免了在多线程环境中锁定的需要。

    构建器可以确保对象即使在构建后直接满足某些不变量。例如,如果您的类有一个name 字段,该字段不能是null,则构建器可以检查此条件并在不满足时构造对象失败。

您也可以通过使用将所有类内容作为参数的构造函数来完成这两件事,但是当您的类有多个要初始化的字段时,这将是非常不可读的。

【讨论】:

以上是关于当我们可以用 setter 做同样的事情时,为啥我们需要使用 builder 设计模式? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 runOnUiThread 做同样的事情时使用处理程序?

当我可以在“git init”之后对“git pull”做同样的事情时,为啥要“git clone”? [复制]

当 XG(跨组)事务可以做同样的工作时,为啥要选择实体组事务?

如果无效元数据可以做同样的事情,为啥需要在 Impala 中刷新

当按位运算符做同样的事情时,为啥要使用逻辑运算符?

为啥 shell=True 和 shell=False 做同样的事情? [复制]