簡體   English   中英

如何用scala中的不可變couterpart替換java可變類?

[英]How can I replace a java mutable class with its immutable couterpart in 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;
}

聯系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;
    }
}

快速回答是您使用參數調用構造函數。 在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())
   );

我現在省略了可選的生日,我們將其添加回Scala版本。

我們仍然有一個可變的聯系人列表,所以讓我們看看它是否正確不變。 我們將使用Scala列表。 首先,scala數據對象:

case class Contact(
  first: String,
  middle: String,
  last: String,
  birthday: Option[Date])

我們有可選的生日作為類型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)
}

此版本以遞歸方式構建ResultSet中所有聯系人的單鏈接列表。 這是不可改變的。

您還可以擁有一個可變構建器 ,它可以生成您正在查找的不可變對象。 如果臨時可變對象保留在其創建范圍內並且它們不會傳播到其他地方,則沒有任何問題。 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*/ ) }
  }
}

它可以用作:

val builder = new PersonBuilder
builder setName "Alex"
builder setAge 42
builder setMarried false
val person = builder build  // The immutable instance

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM