如何用scala中的不可变couterpart替换java可变类?

ScA*_*er2 3 java functional-programming scala

我试图理解如何在scala中使用不可变类作为可变java类的替代.

我的示例用例是在数据库中搜索联系人.当命令性编程时,您将从数据库表中提取每个字段并将其设置在java对象上.

你会如何使用不可变类型和函数样式在Scala中执行此操作?

我知道我可以使用构造函数并创建一个新的对象实例,将所有必需的数据传递给它,但对于大型复杂的数据结构,这似乎并不优雅.

什么是"Scala"/"功能"方法来实现这一目标?或者与构建复杂的不可变类型有关的一些最佳实践是什么?

public List<Contact> search(String firstName, String lastName) throws SQLException {
    List<Contact> contacts = new ArrayList<Contact>();

    Connection con = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
        con = dataSource.getConnection();

        ps = con.prepareStatement("select * from contacts where first_name like ? and last_name like ?");
        ps.setString(1, "%" + firstName + "%");
        ps.setString(1, "%" + lastName + "%");
        rs = ps.executeQuery();

        while (rs.next()) {
            Contact contact = new Contact();
            contact.setFirstName(rs.getString("first_name"));
            contact.setMiddleName(rs.getString("middle_name"));
            contact.setLastName(rs.getString("last_name"));
            Date birthday = rs.getDate("birthday");
            if (birthday != null) {
                contact.setBirthday(new Date(birthday.getTime()));
            }
            contacts.add(contact);
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        rs.close();
        ps.close();
        con.close();
    }
    return contacts;
}
Run Code Online (Sandbox Code Playgroud)

联系POJO

import java.util.Date;

public class Contact {
    private String firstName;
    private String middleName;
    private String lastName;
    private Date birthday;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getMiddleName() {
        return middleName;
    }

    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}
Run Code Online (Sandbox Code Playgroud)

Jed*_*ith 8

快速回答是您使用参数调用构造函数.在Java中:

public class Contact {
  private final String firstName;
  private final String middleName;
  private final String lastName;
  private final Date birthday;

  public Contact(
    String firstName,
    String middleName,
        String lastName,
    Date birthday
  ) {
    this.firstName = firstName;
    this.middleName = middleName;
    this.lastName = lastName;
    this.birthday = birthday;
  }
  … // getters
}

  … inside while loop:
  contacts.add(new Contact(
    rs.getString("first_name"),
    rs.getString("middle_name"),
    rs.getString("last_name"),
    new Date(birthday.getTime())
   );
Run Code Online (Sandbox Code Playgroud)

我现在省略了可选的生日,我们将其添加回Scala版本.

我们仍然有一个可变的联系人列表,所以让我们看看它是否正确不变.我们将使用Scala列表.首先,scala数据对象:

case class Contact(
  first: String,
  middle: String,
  last: String,
  birthday: Option[Date])
Run Code Online (Sandbox Code Playgroud)

我们有可选的生日作为类型sig的一部分作为奖励.

现在让我们定义一个简单的提取器方法,给定一个resultSet:

def contacts(rs: ResultSet) = {
  @annotation.tailrec def loop(cs: List[Contact]): List[Contact] =
    if (!rs.next()) cs else loop(
      Contact(
        rs.getString("first_name"),
        rs.getString("middle_name"),
        rs.getString("last_name"),
        Option(rs.getLong("birthday"))
      ) :: cs)
  loop(Nil)
}
Run Code Online (Sandbox Code Playgroud)

此版本以递归方式构建ResultSet中所有联系人的单链接列表.这是不可改变的.


par*_*tic 6

您还可以拥有一个可变构建器,它可以生成您正在查找的不可变对象.如果临时可变对象保留在其创建范围内并且它们不会传播到其他地方,则没有任何问题.Scala标准库实现使用了大量的.

这是一个简单的例子(虽然这个解决方案在构造函数很大时更有用):

// Here is the immutable class
case class Person( name: String, age: Int, married: Boolean )

// Here comes the mutable builder
class PersonBuilder {
  private var name: Option[String] = None
  private var age: Option[Int] = None
  private var married: Option[Boolean] = None

  def setName( n: String ) = { name = Some(n); this }
  def setAge( a: Int ) = { age = Some(a); this }
  def setMarried( m: Boolean ) = { married = Some(m); this }

  def build() = {
    val person = for( n <- name; a <- age; m <- married ) 
                   yield { Person( n, a, m ) }
    person getOrElse { throw new IllegalStateException( /*msg*/ ) }
  }
}
Run Code Online (Sandbox Code Playgroud)

它可以用作:

val builder = new PersonBuilder
builder setName "Alex"
builder setAge 42
builder setMarried false
val person = builder build  // The immutable instance
Run Code Online (Sandbox Code Playgroud)