Well, why would the code have to be different, and why can't you re-use even the code, and not only the idea? That's because in Java you cannot easily pass functions around. However, in Scala you can. Take, for example, the "loan pattern." It allows to borrow the resource and make sure you close it later. Here is what I mean. You may have thousands of little functions that open the SQL connection, use it, then close it, like in this picture
This screen image is to show off the syntax coloring of Scala code in NetBeans, but here is the same code in plain words:
def doSqlStuff: Unit = {
var conn: Connection = null
try {
val url = "jdbc:mysql://localhost:3306/";
val dbName = "beren";
val driver = "com.mysql.jdbc.Driver";
val userName = "beren";
val password = "beren";
Class.forName(driver).newInstance();
conn = DriverManager.getConnection(url + dbName, userName, password)
val stmt = conn.prepareStatement("insert into stuff (id) values (?) ")
stmt.setString(1, "" + new Date())
stmt.executeUpdate
} catch {
case e: SQLException => {
e.printStackTrace
println("SQLException: " + e.getMessage)
}
case ex: Exception => {
println("Exception: " + ex.getMessage)
}
} finally {
conn.close
}
}
But, only three lines are really important:
val stmt = conn.prepareStatement("insert into stuff (id) values (?) ")
stmt.setString(1, "" + new Date())
stmt.executeUpdate
Nevertheless, because of those three lines I am forced to replicate the boilerplate over and over. If I could somehow pass these lines to my boilerplate code, I would have it so much nicer!
OK, and indeed, it's better when you do it like this. Here is the boiler plate. Now you promise to pass it the function to do the real work.
def doSqlStuffBoilerplate (sqlDoer: Connection => Int): Unit = {
var conn: Connection = null
try {
val url = "jdbc:mysql://localhost:3306/";
val dbName = "beren";
val driver = "com.mysql.jdbc.Driver";
val userName = "beren";
val password = "beren";
Class.forName(driver).newInstance();
conn = DriverManager.getConnection(url + dbName, userName, password)
sqlDoer(conn)
} catch {
case e: SQLException => {
e.printStackTrace
println("SQLException: " + e.getMessage)
}
case ex: Exception => {
println("Exception: " + ex.getMessage)
}
} finally {
conn.close
}
}
Here are the three lines that you will pass as a function,
def sqlDoer(conn: Connection): Int = {
val stmt = conn.prepareStatement("insert into stuff (id) values (?) ")
stmt.setString(1, "" + new Date())
stmt.executeUpdate
}
and this is how to call the method:
def doSqlStuffBetter(): Unit = {
doSqlStuffBoilerplate (sqlDoer)
}
We tried this idea in Java, but the code is unreadable, and we went back to the old way of copying and pasting. With Scala, you can abstract and CODE the design pattern. (Even better is to in-line the function when passing, but I will do it later).
No comments:
Post a Comment