简体   繁体   中英

What is the reasoning behind the Book.scala file contents in simple-rest-scala

In the activator template for simple rest API project in Scala the Book.scala file looks like the following.

package models

import play.api.libs.json.Json

object Book {

  case class Book(name: String, author: String)

  implicit val bookWrites = Json.writes[Book]
  implicit val bookReads = Json.reads[Book]

  var books = List(Book("TAOCP", "Knuth"), Book("SICP", "Sussman, Abelson"))

  def addBook(b: Book) = books = books ::: List(b)
}

Why is there a Book object and a Book case class inside it? Why not just a Book case class (or just a Book class and not a case class)? What advantages/disadvantages are there in the above structure?

I'm sure this is just a small example that somebody put together, and so you shouldn't read too much into it. But it exhibits what some consider an anti-pattern: nesting case classes in other classes. Some best-practices guides, such as this one , suggest avoiding nesting case classes in other classes, and for good reason:

It is tempting, but you should almost never define nested case classes inside another object/class because it messes with Java's serialization. The reason is that when you serialize a case class it closes over the "this" pointer and serializes the whole object, which if you are putting in your App object means for every instance of a case class you serialize the whole world.

And the thing with case classes specifically is that:

  1. one expects a case class to be immutable (a value, a fact) and hence
  2. one expects a case class to be easily serializable

Prefer flat hierarchies.

For example, this small program throws an exception, somewhat unexpectedly:

import java.io._

class Outer {
  case class Inner(a: Int)
}

object Test extends App {
    val inner = (new Outer).Inner(1)
    val oos = new ObjectOutputStream(new FileOutputStream("/tmp/test"))
    oos.writeObject(inner)
    oos.close
}

If the only purpose of this outer Book object is to group together common functionality, a package would be the preferred structure.

Furthermore, even if an object were desired for some other reason, naming that object the same as the inner case class is confusing, especially since case classes automatically generate companion objects. So in this example there is a Book object, a Book.Book case class, and therefore also a Book.Book companion object.

The role of Book object in this code is more like a static book utils/manager class which hold a list of books. You can imagine that this is a Library class, which allow to add books.

The Book case class is just an anonymous class for Book instances. As mz said, it is just an example, for more complicated class, you could move it to a standalone Book class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM