(一)apply的基本使用
不使用new关键字创建对象?
在 Scala 中,apply 方法放在类的伴生对象(object)里,主要起到 工厂方法的作用,能够让使用者在创建该类实例时省去显式的 new 关键字,并且可以通过重载提供多种构造方式。
当写ClassName(arg1,arg2)时,编译器会自动翻译ClassName.apply(arg1,arg2),这可以让实例化代码更简单。
1.定义一对伴生类和伴生对象
2.在伴生对象中还需要实现apply方法,返回伴生类的实例
object Main {
/*
* apply
* apply方法写在伴生对象中,可以在创建对象的时候,省略new关键字
*
* val 对象 = 伴生类() <===> 伴生对象.apply()
*/
class Person() {
}
object Person {
def apply(): Person = {
println("apply ……")
new Person()
}
}
def main(args: Array[String]): Unit = {
// 创建一个类的对象
// val p1 = new Person()
val p1 = Person() // 自动调用apply方法
val p2 = Person()
println(p1)
println(p2)
}
}
apply 方法的主要用途:
- 简化对象创建:省略
new关键字 - 工厂模式:控制对象的创建过程
- 集合初始化:如
List(1,2,3)、Array("a","b") - 案例类:Scala 自动为 case class 生成 apply 方法
apply 方法是 Scala 中非常重要的语法糖,它让代码更加简洁和函数式。
(二)apply实现单例模式
object Main {
/*
* apply
* apply方法写在伴生对象中,可以在创建对象的时候,省略new关键字
* 实现单例模式
* 在伴生对象中 创建一个对象:在apply方法中返回它
*/
class Person() {
println("主构造器被调用......")
}
object Person {
val p = new Person()
def apply(): Person = {
p
}
}
def main(args: Array[String]): Unit = {
// 创建一个类的对象
// val p1 = new Person()
val p1 = Person() // 自动调用apply方法
val p2 = Person()
println(p1)
println(p2)
println(p1 == p2) // true
}
}
在代码中 isEmpty判断是否为空,Some()用来包装一个对象,如果这个对象为空,就得到None对象,否则就返回这个对象。
这个单例模式实现的关键点:
- 私有构造函数:
class Person private ()- 防止外部直接new Person() - 单例实例:
private val instance = new Person()- 在伴生对象中创建唯一实例 - apply方法:返回同一个单例实例
- 验证:
p1 == p2返回true,证明是同一个对象 - 构造器只调用一次:证明确实实现了单例
(三)案例-日志类
object Main {
/*
实现一个日志类:Logger
1. 把一些操作信息写入到文本文件中。
2. 实现单例模式
*/
class Logger(filename: String) {
def log(content: String): Unit = {
println(s"${content}")
}
}
object Logger {
// 定义一个对象
var instance: Option[Logger] = None
def apply(filename: String): Logger = {
if (instance.isEmpty) {
instance = Some(new Logger(filename))
}
instance.get
}
}
def main(args: Array[String]): Unit = {
val logger1 = Logger("test.log")
val logger2 = Logger("test.log")
println(logger2 == logger1) // true
logger1.log("2005-11-4 09:06:03 上scala课")
logger2.log("2005-11-5 09:06:03 运动会")
}
}
这个日志单例模式实现的关键点:
- 单例实例管理:使用
Option[Logger]来管理单例实例 - 懒加载:只有在第一次调用时才创建实例
- apply方法:提供统一的实例获取接口
- 验证单例:
logger2 == logger1返回true - 日志功能:
log方法输出日志内容
即使多次调用 Logger("test.log"),也只会创建一个实例,实现了真正的单例模式。
(四)案例-改进日志类
具体实现文件的创建和写入功能。
接下来,我们去实现文件的创建和写入功能。这里需要用java.io.FileWriter类。我们通过这个类来创建一个writer对象,来将具体的日志内容写入指定的文件。
import java.io.FileWriter
object Main {
/*
实现一个日志类:Logger
1. 把一些操作信息写入到文本文件中。导入使用 java.io.FileWriter
2. 实现单例模式
*/
class Logger(filename: String) {
def log(content: String): Unit = {
// 把内容写入一个文件中
val writer = new FileWriter(filename, true)
writer.write(content + "\n")
writer.close()
// println(s "${content} ")
}
}
object Logger {
// 定义一个对象
var instance: Option[Logger] = None
def apply(filename: String): Logger = {
if (instance.isEmpty) {
instance = Some(new Logger(filename))
}
instance.get
}
}
def main(args: Array[String]): Unit = {
val logger1 = Logger("test.log")
// val logger2 = Logger("test.log")
// println(logger2 == logger1)
logger1.log("2005-11-4 09:06:03 上scala课")
logger1.log("2005-11-5 09:06:03 运动会")
logger1.log("2005-11-6 09:06:03 休息")
}
}
这个文件日志单例模式实现的关键点:
- 导入 FileWriter:
import java.io.FileWriter - 文件写入:使用
FileWriter将日志内容写入文件 - 追加模式:
true参数表示追加内容而不是覆盖 - 单例模式:确保只有一个日志实例操作同一个文件
- 换行写入:每个日志内容后添加
\n换行符
每次调用 log 方法都会将内容追加到指定的日志文件中。