2013-07-09 5 views
7

나는스칼라 "갱신"불변 객체 모범 사례

var user = DAO.getUser(id) 
user.name = "John" 
user.email ="[email protected]" 
// logic on user 

같은 것을 쓸 수 있습니다.

나는 몇 가지 방법이 새 속성

가장 좋은 방법은 무엇입니까로 새로운 객체를 생성이

  1. 경우 클래스 사본 (로 changeName 같은)
  2. 방법을 수행하기 위해 알아?

    그리고 하나 더 질문드립니다. 원본 개체와 관련하여 "변경"을 수행하는 기존 기술이 있습니까 (예 : 업데이트 문 생성)?

+0

변경 사항을 얻으려면 Event Sourcing을 사용할 수 있습니다. –

답변

8

언급 한 두 가지 방식은 각각 기능적 및 OO 패러다임에 속합니다. 스칼라에서 사례 클래스로 표현되는 추상 데이터 유형으로 기능적 분해를 선호하는 경우 복사 방법을 선택하십시오. 돌연변이 체를 사용하는 것은 좋은 방법이 아닙니다. Java/C#/C++ 방식으로 다시 돌아갈 수 있습니다.

case class Person(name: String, age: String) 

후 더 consise 인 ADT 경우 클래스를 만드는 한편

같은 :

class Person(_name: String, _age: String) { 
    var name = _name 
    var age = _a 

    def changeName(newName: String): Unit = { name = newName } 
    // ... and so on 
} 

(안 최고의 필수적 코드가 짧아 질 수 있지만, 삭제할 수 있습니다).

class Person(val name: String, 
      val age: String) {  
    def changeName(newName: String): Unit = new Person(newName, age) 
    // ... and so on 
} 

그러나 여전히 경우 클래스의 방법은 더 consise입니다 : 원인의

는 각 호출에 새로운 개체를 반환, 뮤 테이터 또 다른 방법이있다.

그리고 동시/병렬 프로그래밍으로 넘어 간다면, 불변 값을 가진 기능적 개념이 훨씬 더 좋음을 알 수있을 것이며, 현재 객체의 상태를 추측 할 수 있습니다. 니아

업데이트

덕분에, 두 가지를 언급하는 것을 잊었다.

렌즈 가장 기본적인 수준에서
는, 렌즈는 다음과 같이 불변 데이터에 대한 getter 및 setter의 일종과 같습니다 그것은

case class Lens[A,B](get: A => B, set: (A,B) => A) { 
    def apply(a: A) = get(a) 
    // ... 
} 

즉. 렌즈는 get과 set의 두 가지 기능을 포함하는 객체입니다. get은 A를 취해 B를 반환합니다. set은 A와 B를 취하여 A를 반환합니다. B가 A에 포함 된 값이라는 것을 쉽게 알 수 있습니다. 인스턴스를 전달하면 값을 반환합니다. 우리가 A와 B를 통과 시키면 A에서 값 B를 갱신하고 변경을 반영하는 새로운 A를 리턴합니다. 편의상 get에 별칭이 적용됩니다.Scalaz 렌즈 케이스 클래스이 하나가 ofcause의 shapeless 라이브러리라는 기록에서 유래

기록
에 좋은 intro 있습니다. 연관성의 HLists로 모델화 된 확장 가능한 레코드의 구현. 키는 싱글 톤 유형을 사용하여 인코딩되며 해당 값의 유형을 완전히 결정합니다 (예 : github에서).

object author extends Field[String] 
object title extends Field[String] 
object price extends Field[Double] 
object inPrint extends Field[Boolean] 

val book = 
    (author -> "Benjamin Pierce") :: 
    (title -> "Types and Programming Languages") :: 
    (price -> 44.11) :: 
    HNil 

// Read price field 
val currentPrice = book.get(price) // Inferred type is Double 
currentPrice == 44.11 

// Update price field, relying on static type of currentPrice 
val updated = book + (price -> (currentPrice+2.0)) 

// Add a new field 
val extended = updated + (inPrint -> true) 
+3

[렌즈] (https://blog.stackmob.com/2012/02/an-introduction-to-lenses-in-scalaz/)에 세 번째 방법을 추가 할 수 있습니다. 새로운 답변에는 충분하지 않지만 언급할만한 가치가 있습니다. – senia

+0

@senia 덕분에 렌즈와 형태가없는 레코드가 추가되었습니다. – 4lex1v