Builder设计模式和Factory设计模式有什么区别?
哪一个更有利,为什么?
如果我想测试和比较/对比这些模式,我如何将我的发现表示为图表?
design-patterns factory-method factory-pattern builder-pattern
我最近开始阅读Joshua Bloch撰写的Effective Java.我发现Builder模式的概念[书中的第2项]非常有趣.我试图在我的项目中实现它,但有编译错误.以下是我试图做的事情:
具有多个属性及其构建器类的类:
public class NutritionalFacts {
private int sodium;
private int fat;
private int carbo;
public class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder(int s) {
this.sodium = s;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo …Run Code Online (Sandbox Code Playgroud) 有没有办法在IntelliJ中自动编写Builder模式?
例如,给定这个简单的类:
class Film {
private String title;
private int length;
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return this.title;
}
public void setLength(int length) {
this.length = length;
}
public int getLength() {
return this.length;
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法,我可以让IDE生成这个或类似的:
public class FilmBuilder {
Film film;
public FilmBuilder() {
film = new Film();
}
public FilmBuilder withTitle(String title) {
film.setTitle(title);
return this;
}
public FilmBuilder withLength(int length) {
film.setLength(length);
return this;
}
public Film build() …Run Code Online (Sandbox Code Playgroud) code-generation design-patterns intellij-idea builder-pattern
在Java中,您可以使用构建器模式提供更具可读性的方法来实例化具有许多参数的类.在构建器模式中,构造一个配置对象,其中包含设置命名属性的方法,然后使用它来构造另一个对象.
Python中的等价物是什么?是模仿相同实现的最佳方法吗?
最近我搜索了一种初始化复杂对象的方法,而没有将大量参数传递给构造函数.我尝试使用构建器模式,但我不喜欢这样的事实,即如果我确实设置了所有需要的值,我无法在编译时检查.
当我使用构建器模式创建我的Complex对象时,创建更"类型安全",因为它更容易看到用于什么参数:
new ComplexBuilder()
.setFirst( "first" )
.setSecond( "second" )
.setThird( "third" )
...
.build();
Run Code Online (Sandbox Code Playgroud)
但现在我遇到了问题,我很容易错过一个重要的参数.我可以在build()方法中检查它,但这只是在运行时.如果我错过了什么,在编译时没有什么可以警告我.
现在我的想法是创建一个构建器,"提醒"我是否错过了所需的参数.我的第一次尝试看起来像这样:
public class Complex {
private String m_first;
private String m_second;
private String m_third;
private Complex() {}
public static class ComplexBuilder {
private Complex m_complex;
public ComplexBuilder() {
m_complex = new Complex();
}
public Builder2 setFirst( String first ) {
m_complex.m_first = first;
return new Builder2();
}
public class Builder2 {
private Builder2() {}
Builder3 setSecond( String …Run Code Online (Sandbox Code Playgroud) 构建器模式在创建不可变对象时很流行,但是创建构建器会产生一些编程开销.所以我想知道为什么不简单地使用配置对象.
构建器的用法如下所示:
Product p = Product.Builder.name("Vodka").alcohol(0.38).size(0.7).price(17.99).build();
Run Code Online (Sandbox Code Playgroud)
很明显,这是非常易读和简洁的,但您必须实现构建器:
public class Product {
public final String name;
public final float alcohol;
public final float size;
public final float price;
private Product(Builder builder) {
this.name = builder.name;
this.alcohol = builder.alcohol;
this.size = builder.size;
this.price = builder.price;
}
public static class Builder {
private String name;
private float alcohol;
private float size;
private float price;
// mandatory
public static Builder name(String name) {
Builder b = new Builder();
b.name = name;
return b;
} …Run Code Online (Sandbox Code Playgroud) 我已经看到这个问题在这里和那里出现了几次,但我从来没有找到并回答我很高兴.
来自维基百科:
Builder专注于逐步构建复杂对象.Abstract Factory强调一系列产品对象(简单或复杂).Builder将产品作为最后一步返回,但就Abstract Factory而言,产品会立即返回.
但对客户来说不是一回事吗?一旦它被构建,他就会获得完整的对象,所以对他来说没有额外的功能.
我看到它的唯一方法是作为一种方式或按步骤组织构造函数代码,以强制实现构建器的结构.哪个好,但从抽象工厂那里迈出的一步很难.
来自维基百科的下一篇文章是一个很好的参考,以达到我的观点:
通常,设计开始使用工厂方法(不太复杂,可定制,子类增加),并逐渐向抽象工厂,原型或构建器(更灵活,更复杂)发展,因为设计师发现需要更多灵活性的地方.
如果是这样,那么您需要在系统中引入哪种复杂性,从而将抽象工厂更改为构建器?
我的观点是,我无法找到并举例说明抽象工厂是否足够,而你需要一个Builder.
编辑:我不担心被错误的顺序调用,因为这是通过使用多个接口强制执行,我只是担心终端方法被调用.
我正在使用构建器模式在我们的系统中创建权限.我选择了一个生成器模式,因为安全是我们的产品很重要(涉及未成年人这么COPPA等),我觉得这是迫切需要的权限是可读的,并认为可读性是极为重要的(即使用一个流畅的风格构建器模式而不是具有6个值的单个函数).
代码如下所示:
permissionManager.grantUser( userId ).permissionTo( Right.READ ).item( docId ).asOf( new Date() );
Run Code Online (Sandbox Code Playgroud)
这些方法填充私有辅助bean,在终端方法(即asOf)提交数据库权限时; 如果那个方法没有被调用就没有任何反应.有时,开发人员会忘记调用终端方法,该方法不会导致编译器错误,并且很容易错过快速阅读/略读代码.
我该怎么做才能防止这个问题?我不想返回需要保存的Permission对象,因为这会引入更多噪音并使权限代码更难以阅读,跟踪,跟踪和理解.
我已经考虑过在终端命令标记的后台上放置一个标志.然后,检查finalize方法中的标志,如果创建对象而没有持久化,则写入日志.(我知道finalize不能保证运行,但这是我能想到的最好的.)
例如,如果我有一个构建器,那么我可以像这样创建对象:
Node node = NodeBuilder()
.withName(someName)
.withDescription(someDesc)
.withData(someData)
.build();
Run Code Online (Sandbox Code Playgroud)
如何确保在构建方法之前已经设置了用于构建对象的所有变量?
例如:
Node node = NodeBuilder()
.withName(someName)
.build();
Run Code Online (Sandbox Code Playgroud)
不是一个有用的节点,因为尚未设置描述和数据.
我使用构建器模式的原因是因为没有它,我需要很多构造函数的组合.例如,可以通过获取Field对象来设置名称和描述,并且可以使用文件名设置数据:
Node node = NodeBuilder()
.withField(someField) //Sets name and description
.withData(someData) //or withFile(filename)
.build(); //can be built as all variables are set
Run Code Online (Sandbox Code Playgroud)
否则将需要4个构造函数(字段,数据),(字段,文件名),(名称,描述,数据),(名称,描述,文件名).当需要更多参数时会变得更糟.
这些"方便"方法的原因是因为必须构建多个节点,因此它可以节省大量重复的行,如:
Node(modelField.name, modelField.description, Data(modelFile)),
Node(dateField.name, dateField.description, Data(dateFile)),
//etc
Run Code Online (Sandbox Code Playgroud)
但是在某些情况下,需要使用非来自文件的数据构建节点,和/或名称和描述不基于字段.也可能有多个节点共享相同的值,因此不是:
Node(modelField, modelFilename, AlignLeft),
Node(dateField, someData, AlignLeft),
//Node(..., AlignLeft) etc
Run Code Online (Sandbox Code Playgroud)
你可以有:
LeftNode = NodeBuilder().with(AlignLeft);
LeftNode.withField(modelField).withFile(modelFilename).build(),
LeftNode.withField(dateField).withData(someData).build()
Run Code Online (Sandbox Code Playgroud)
所以我认为我的需求与构建器模式非常匹配,除了构建不完整对象的能力.由于上述原因,"在构造函数中放置必需参数并具有可选参数的构建器方法"的正常建议不适用于此处.
实际问题:如何在编译时调用构建之前确保已设置所有参数?我正在使用C++ 11.
(在运行时,我可以为每个参数设置一个标志位,并声明所有标志都在构建中设置)
或者是否有一些其他模式来处理大量的构造函数组合?
存在哪些工具/库将采用结构并自动生成不可变包装器以及用于逐步构建新实例的"构建器"类?
输入示例:
struct Foo
{
public int apples;
public int oranges;
public Foo Clone() {return (Foo) base.MemberwiseClone();}
}
Run Code Online (Sandbox Code Playgroud)
示例输出:
public class ImmutableFoo // could probably be a struct
{
private Foo snapshot;
internal ImmutableFoo(Foo value) { this.snapshot = value; }
public FooBuilder Builder() { return new FooBuilder(snapshot); }
public int Apples { get { return snapshot.apples; } }
public int Oranges { get { return snapshot.oranges; } }
}
public class FooBuilder
{
private Foo state;
public int Apples { …Run Code Online (Sandbox Code Playgroud) c# language-agnostic design-patterns immutability builder-pattern