2013-07-09 9 views
7

With a zmienny obiektu można napisać coś podobnegoScala „Update” niezmienne obiektów najlepszych praktyk

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

Jeśli użytkownik jest niezmienna następnie trzeba sklonować \ skopiować go na każdej operacji zmiany.

Znam kilka sposobów, aby wykonać tę

  1. case class kopię
  2. metody (jak changeName), który tworzy nowy obiekt z nowym własności

Jaka jest najlepsza praktyka?

Jeszcze jedno pytanie. Czy istnieje jakaś technika uzyskiwania "zmian" w stosunku do oryginalnego obiektu (na przykład w celu wygenerowania instrukcji aktualizacji)?

+0

aby zmiany, można użyć Event Sourcing. –

Odpowiedz

8

Oba wspomniane sposoby należą odpowiednio do paradygmatów funkcjonalnych i OO. Jeśli wolisz rozkład funkcjonalny z abstrakcyjnym typem danych, który w Scali jest reprezentowany przez klasy przypadków, wybierz metodę kopiowania. Używanie mutatorów nie jest dobrą praktyką w mojej opcji, ponieważ spowoduje to powrót do stylu życia Java/C#/C++.

Z drugiej strony podejmowania ADT klasę case jak

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

jest bardziej zwarte wtedy:

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

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

(nie najlepszy kod imperatyw, może być krótsza, ale jasne).

Przyczyny istnieje inny sposób z mutatorów, żeby powrócić nowy obiekt na każdej rozmowy:

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

Ale nadal klasa przypadek sposobem jest bardziej zwarte.

A jeśli pójdziecie dalej, do programowania równoległego/równoległego, zobaczycie, że funkcjonalna koncepcja z niezmienną wartością jest o wiele lepsza, a następnie próbuje odgadnąć, w jakim stanie obecnie znajduje się obiekt.

Aktualizacja

Dzięki Senia, zapomniałem wspomnieć o dwóch rzeczach.

Soczewki
Na najbardziej podstawowym poziomie, soczewki są rodzajem pobierające i ustawiające dla danych niezmiennych i wygląda następująco:

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

To jest to. Obiektyw jest obiektem, który zawiera dwie funkcje: get i set. get pobiera A i zwraca zestaw B. pobiera A i B i zwraca nowy A. Łatwo zauważyć, że typ B jest wartością zawartą w A. Kiedy przekazujemy instancję, aby uzyskać, zwracamy tę wartość. Kiedy przekazujemy A i B do ustawienia, aktualizujemy wartość B w A i zwracamy nowe A odzwierciedlające zmianę. Dla wygody uzyskuje się aliasy do zastosowania.Jest dobry intro do Scalaz Lens Case klasy

Records
Ten jeden, ofcause, pochodzi z biblioteki shapeless i nazwał Records. Implementacja rozszerzalnych rekordów modelowanych jako HLists stowarzyszeń. Klawisze są kodowane za pomocą singleton rodzajów iw pełni określić rodzaje odpowiadających im wartości (ex od 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

Możesz dodać trzeci sposób odpowiedzi: [soczewki] (https://blog.stackmob.com/2012/02/an-introduction-to-lenses-in-scalaz/). Nie wystarczy na nową odpowiedź, ale warto o tym wspomnieć. – senia

+0

@senia dzięki dodaniu soczewek i bezkształtnych nagrań – 4lex1v

Powiązane problemy