构建器模式和构造函数的区别
Difference between builder pattern and constructor
构建器模式只是一种构建对象的方式,类似于构造函数的作用,那么为什么要使用构建器模式而不是普通的旧构造函数呢?
The telescoping constructor anti-pattern occurs when the increase of
object constructor parameter combination leads to an exponential list
of constructors. Instead of using numerous constructors, the builder
pattern uses another object, a builder, that receives each
initialization parameter step by step and then returns the resulting
constructed object at once
因此,如果我有一个需要很多构造参数的对象,并且这些参数需要以各种组合形式出现(因此使某些参数成为可选参数),那么构建器是一个很好的方法。
例如我可以为一个对象创建多个不同的构造函数,或者我可以执行以下操作:
new ObjectBuilder().withParam1(1).withParam4(4).withParam19(19).build();
从而允许我select所需的参数,而不必定义许多不同的构造函数。另请注意,上面的内容可以让您填充构建器,并多次设置 parameters/call build()
以轻松创建一组相关对象。
在构建器中构建对象 class 允许在一个地方封装与构建对象相关的逻辑。此外,与使用常规构造函数相比,您可以更轻松地处理对象构造所需的依赖关系。
换句话说 - 如果构建一个对象很复杂,并且依赖项很少 - 使用构建器模式,如果对象构建很简单(很少的逻辑和只有很少的参数) - 使用构造函数。
我同意您的观点,即 Builder
实际上只是一个美化的构造函数,而 "builder pattern is just a way to build an object similar to what a constructor does"。
但是,在以下几个场景中,构建 object 的复杂性使得 Builder
的使用引人注目。
Object 在一段时间内收集的依赖项
在 Java 中,StringBuilder
通常用于在一段时间内构建一个字符串,或者更确切地说,在一个复杂的过程中。例如,如果服务器通过套接字与客户端通信,并且想要将一些客户端响应附加到字符串,而不是其他响应,并且可能删除以前附加的某些响应,则 StringBuilder
class 可以用来这样做。在client/serversession结束时,服务器可以调用StringBuilder#toString
来获取构建的String
.
很多参数
如果构造函数有几十个参数,使用构建器可能会使代码更具可读性或易于维护。
例如
new Foo(1,2,3,4,5,6,7,8,9,10,11,12)
比
Foo.newBuilder()
.bar(1)
.bar(2)
.quux(3)
...
.build()
构建object图
与"lots of parameters"场景类似,我认为构建器最引人注目的场景是在构建复杂的object图时。这个问题的其他答案是指伸缩anti-pattern。这种情况(构建一个复杂的 object 图)可能导致 "telescoping",Builder
有助于解决这个问题。
例如,假设您有一个 object-oriented 管道接口,其中 Pipeline
依赖于 Sequence
,而 Sequence
又依赖于 Stage
。 PipelineBuilder
不仅会为 Pipeline
的构造函数提供一个很好的包装器,而且还会围绕 Sequence
和 Stage
的构造函数提供一个很好的包装器,允许您编写一个复杂的 Pipeline
来自单个 Builder
界面。
而不是像这样伸缩构造函数:
new Pipeline(
new Sequence(
new Stage(
new StageFunction() {
public function execute() {...}
}
),
new Stage(
new StageFunction() {
public function execute() {...}
}
)
)
)
A PipelineBuilder
将允许您 "collapse" telescope。
Pipeline.newBuilder()
.sequence()
.stage(new StageFunction () {
public function execute() {...}
})
.stage(new StageFunction () {
public function execute() {...}
})
.build()
(尽管我以反映伸缩构造函数的方式使用缩进,但这只是装饰性的,而不是结构性的。)
constructor构造你需要的对象,而builder是helper object构造你需要的。我觉得太可怕了!
- 这与自然而然的、熟知的对象创建方法相矛盾。他们接下来会想出什么新办法?
- 您必须创建两个,而不是创建一个对象。
- 完全没有必要!我们总是必须为函数参数准备变量,而且我们从未使用过构建器。
例如:
// a class with ctor that takes lots of params
class Params
{
Params(int,int,int,String,char,boolean,int){}
}
// We dont need a builder.
// A builder will do the same following thing.
int p1 = 20;
int p2 = 40 + 40;
int p3 = (67 >> 1) * 3;
String p4 = "go" + "to" + "church";
char p5 = ' ' == 32 ? '5' : '7';
boolean p6 = true;
int p7 = MATCH_PARAMS;
new Params(p1,p2,p3,p4,p5,p6,p7);
//There is also this design pattern
new Params(
20,
40 + 40,
(67 >> 1) * 3,
"go" + "to" + "church",
' ' == 32 ? '5' : '7',
true,
MATCH_PARAMS
);
归根结底,如果您是建设者的粉丝,那没问题。但是当 Android 使构造函数被弃用时,我不喜欢那样。喜欢,类型类型;已弃用。
构建器模式只是一种构建对象的方式,类似于构造函数的作用,那么为什么要使用构建器模式而不是普通的旧构造函数呢?
The telescoping constructor anti-pattern occurs when the increase of object constructor parameter combination leads to an exponential list of constructors. Instead of using numerous constructors, the builder pattern uses another object, a builder, that receives each initialization parameter step by step and then returns the resulting constructed object at once
因此,如果我有一个需要很多构造参数的对象,并且这些参数需要以各种组合形式出现(因此使某些参数成为可选参数),那么构建器是一个很好的方法。
例如我可以为一个对象创建多个不同的构造函数,或者我可以执行以下操作:
new ObjectBuilder().withParam1(1).withParam4(4).withParam19(19).build();
从而允许我select所需的参数,而不必定义许多不同的构造函数。另请注意,上面的内容可以让您填充构建器,并多次设置 parameters/call build()
以轻松创建一组相关对象。
在构建器中构建对象 class 允许在一个地方封装与构建对象相关的逻辑。此外,与使用常规构造函数相比,您可以更轻松地处理对象构造所需的依赖关系。
换句话说 - 如果构建一个对象很复杂,并且依赖项很少 - 使用构建器模式,如果对象构建很简单(很少的逻辑和只有很少的参数) - 使用构造函数。
我同意您的观点,即 Builder
实际上只是一个美化的构造函数,而 "builder pattern is just a way to build an object similar to what a constructor does"。
但是,在以下几个场景中,构建 object 的复杂性使得 Builder
的使用引人注目。
Object 在一段时间内收集的依赖项
在 Java 中,StringBuilder
通常用于在一段时间内构建一个字符串,或者更确切地说,在一个复杂的过程中。例如,如果服务器通过套接字与客户端通信,并且想要将一些客户端响应附加到字符串,而不是其他响应,并且可能删除以前附加的某些响应,则 StringBuilder
class 可以用来这样做。在client/serversession结束时,服务器可以调用StringBuilder#toString
来获取构建的String
.
很多参数
如果构造函数有几十个参数,使用构建器可能会使代码更具可读性或易于维护。
例如
new Foo(1,2,3,4,5,6,7,8,9,10,11,12)
比
Foo.newBuilder()
.bar(1)
.bar(2)
.quux(3)
...
.build()
构建object图
与"lots of parameters"场景类似,我认为构建器最引人注目的场景是在构建复杂的object图时。这个问题的其他答案是指伸缩anti-pattern。这种情况(构建一个复杂的 object 图)可能导致 "telescoping",Builder
有助于解决这个问题。
例如,假设您有一个 object-oriented 管道接口,其中 Pipeline
依赖于 Sequence
,而 Sequence
又依赖于 Stage
。 PipelineBuilder
不仅会为 Pipeline
的构造函数提供一个很好的包装器,而且还会围绕 Sequence
和 Stage
的构造函数提供一个很好的包装器,允许您编写一个复杂的 Pipeline
来自单个 Builder
界面。
而不是像这样伸缩构造函数:
new Pipeline(
new Sequence(
new Stage(
new StageFunction() {
public function execute() {...}
}
),
new Stage(
new StageFunction() {
public function execute() {...}
}
)
)
)
A PipelineBuilder
将允许您 "collapse" telescope。
Pipeline.newBuilder()
.sequence()
.stage(new StageFunction () {
public function execute() {...}
})
.stage(new StageFunction () {
public function execute() {...}
})
.build()
(尽管我以反映伸缩构造函数的方式使用缩进,但这只是装饰性的,而不是结构性的。)
constructor构造你需要的对象,而builder是helper object构造你需要的。我觉得太可怕了!
- 这与自然而然的、熟知的对象创建方法相矛盾。他们接下来会想出什么新办法?
- 您必须创建两个,而不是创建一个对象。
- 完全没有必要!我们总是必须为函数参数准备变量,而且我们从未使用过构建器。
例如:
// a class with ctor that takes lots of params
class Params
{
Params(int,int,int,String,char,boolean,int){}
}
// We dont need a builder.
// A builder will do the same following thing.
int p1 = 20;
int p2 = 40 + 40;
int p3 = (67 >> 1) * 3;
String p4 = "go" + "to" + "church";
char p5 = ' ' == 32 ? '5' : '7';
boolean p6 = true;
int p7 = MATCH_PARAMS;
new Params(p1,p2,p3,p4,p5,p6,p7);
//There is also this design pattern
new Params(
20,
40 + 40,
(67 >> 1) * 3,
"go" + "to" + "church",
' ' == 32 ? '5' : '7',
true,
MATCH_PARAMS
);
归根结底,如果您是建设者的粉丝,那没问题。但是当 Android 使构造函数被弃用时,我不喜欢那样。喜欢,类型类型;已弃用。