不使用具有长参数列表的构造函数构建大型不可变对象

11 浏览
0 Comments

不使用具有长参数列表的构造函数构建大型不可变对象

我有一些大型(超过3个字段)的对象,可以且应该是不可变的。每次遇到这种情况时,我倾向于创建构造函数的拼凑,参数列表很长。

这感觉不对,使用起来很困难,可读性受到影响。

如果字段是某种集合类型,比如列表,情况就更糟了。一个简单的addSibling(S s)会极大地简化对象的创建,但会使对象变为可变的。

在这种情况下,你们都使用什么解决方案?

我使用的是Scala和Java,但我认为这个问题与语言无关,只要语言是面向对象的。

我能想到的解决方案有:

  1. “构造函数的拼凑”
  2. 构建者模式
0
0 Comments

在上面的代码中,我们定义了一个名为Person的case class,它有四个参数:name,married,espouse和children。这个case class还有两个方法:marriedTo和addChild。marriedTo方法的作用是将该Person对象的married属性设置为true,并将espouse属性设置为Some(whom),其中whom是传入的参数。addChild方法的作用是将传入的参数添加到该Person对象的children属性中。

代码的执行结果是创建了一个名为res1的Person对象,它的属性值为Person(Joseph,true,Some(Mary),Set(Jesus))。

虽然这个代码有一些问题。例如,尝试将espouse的类型改为Option[Person],然后尝试让两个人互相结婚。我无法想到解决这个问题的方法,除非使用一个私有变量和/或一个私有构造函数加上一个工厂方法。

解决这个问题的一种方法是使用私有变量和私有构造函数加上一个工厂方法。我们可以将Person类的构造函数设为私有,并创建一个名为createPerson的工厂方法,该方法接受name、married、espouse和children作为参数,并返回一个新的Person对象。在工厂方法内部,我们可以根据传入的参数来判断是否满足结婚的条件,如果满足则设置married和espouse属性,否则将其设置为默认值。最后,我们可以通过调用工厂方法来创建Person对象,而不是直接调用构造函数。

这样,我们就可以避免在构造函数中使用长参数列表,同时也能够解决两个人互相结婚的问题。

下面是使用私有变量、私有构造函数和工厂方法来解决这个问题的代码示例:

case class Person private (name: String, 
                  married: Boolean, 
                  espouse: Option[Person], 
                  children: Set[String]) {
  def marriedTo(whom: Person) = this.copy(married = true, espouse = Some(whom))
  def addChild(whom: String) = this.copy(children = children + whom)
}
object Person {
  def createPerson(name: String, married: Boolean = false, espouse: Option[Person] = None, children: Set[String] = Set.empty): Person = {
    if (married && espouse.isDefined) {
      new Person(name, married, espouse, children)
    } else {
      new Person(name, false, None, children)
    }
  }
}
val person1 = Person.createPerson("Joseph")
val person2 = Person.createPerson("Mary")
val marriedPersons = person1.marriedTo(person2)
val finalPerson = marriedPersons.addChild("Jesus")
println(finalPerson)

这样,我们就可以通过工厂方法createPerson来创建Person对象,并且可以在工厂方法内部进行条件判断,从而避免了构造函数中使用长参数列表的问题。同时,我们还解决了两个人互相结婚的问题。

文章完。

0
0 Comments

在Scala 2.8中,可以使用命名参数、默认参数以及案例类上的copy方法来构建大型的不可变对象。下面是一些示例代码:

case class Person(name: String, age: Int, children: List[Person] = List()) {
  def addChild(p: Person) = copy(children = p :: this.children)
}
val parent = Person(name = "Bob", age = 55)
  .addChild(Person("Lisa", 23))
  .addChild(Person("Peter", 16))

+1 发明了Scala语言。是的,这是对声誉系统的滥用,但...哎呀...我太喜欢Scala了,所以我不得不这样做。 🙂

哦,天啊...我刚刚回答了几乎相同的东西!好吧,我和你们在一起。:-)不过,我不知道为什么之前没看到你的答案... <耸肩>

问题的原因:

在Scala 2.8之前的版本中,构建大型不可变对象时,需要使用长参数列表的构造函数。这样的构造函数很难理解和维护,而且在创建对象时需要提供所有参数的默认值。这使得代码变得冗长和难以阅读。

解决方法:

Scala 2.8引入了命名参数、默认参数和copy方法的支持,使得构建大型不可变对象变得更加容易和简洁。通过使用命名参数,可以在创建对象时只提供需要的参数,而不必按照特定顺序提供所有参数。默认参数允许在创建对象时省略某些参数,如果省略,则使用参数的默认值。copy方法允许在创建对象的基础上创建一个新对象,同时可以修改某些属性的值。

以案例类Person为例,可以通过使用命名参数和copy方法来构建一个包含子对象的父对象。在Person类中定义了一个addChild方法,该方法通过调用copy方法来创建一个新的Person对象,并将子对象添加到children列表中。通过这种方式,可以在不修改原始对象的情况下构建出一个新的对象。

在上面的示例代码中,首先创建了一个名为parentPerson对象,然后通过调用addChild方法来添加子对象。每次调用addChild方法时,都会创建一个新的Person对象,该对象包含了之前的子对象,并添加了一个新的子对象。这种方式可以轻松地构建出一个包含多个子对象的大型不可变对象,而不需要使用长参数列表的构造函数。

通过使用命名参数、默认参数和copy方法,可以简化大型不可变对象的构建过程,使代码更易于理解和维护。这种方式也使得代码更具可读性和可扩展性,同时提高了开发效率。

0
0 Comments

大建筑物,不使用具有长参数列表的构造函数进行构建的问题是如何解决的?

问题的原因:

- 大量的构造函数参数列表使得代码难以阅读和维护。

- 构造函数参数列表的长度可能会增加,导致代码冗长而难以理解。

- 构造函数参数之间的依赖关系可能很复杂,使得构造过程更加混乱。

解决方法:

- 使用流畅接口(fluent interface)来创建大且不可变的对象。

- 流畅接口的正确实现可以帮助解决上述问题。

- 流畅接口通过链式调用的方式来设置对象的属性,使得代码更加易读。

- 只有在调用build()方法时,才会真正创建对象,因此对象可以是不可变的。

解决方法的实现示例:

- 创建一个工厂类FooFactory,用于创建Foo对象。

- 在FooFactory中定义私有构造函数和静态create()方法,用于创建FooFactory实例。

- 在FooFactory中定义withXXX()方法,用于设置Foo对象的属性,并返回FooFactory实例。

- 在FooFactory中定义build()方法,用于最终构建Foo对象并返回。

实现示例代码如下:

// FooFactory类
private class FooFactory {
    // 私有构造函数
    private FooFactory() {
    }
    
    // 创建FooFactory实例的静态方法
    public static FooFactory create() {
        return new FooFactory();
    }
    
    // 设置颜色属性的方法
    public FooFactory withColor(Color color) {
        this.color = color;
        return this;
    }
    
    // 构建Foo对象的方法
    public Foo build() {
        return new FooImpl(color, and, all, the, other, parameters, go, here);
    }
}
// 使用流畅接口创建Foo对象
final Foo immutable = FooFactory.create()
    .withColor(Color.BLUE)
    .withArea(234)
    .withInterspacing(12)
    .build();

通过使用流畅接口和工厂类,我们可以更容易地创建大且不可变的对象,同时使代码更易读和维护。

0