学习Kotlin之AnkoLogger

2017-07-13  本文已影响618人  Thresh0ld

根据AnkoLogger里的理念自己写了一个Logger。主要目的还是为了学习巩固Kotlin

  1. 先看Logger接口
interface Logger {
    val tag: String
        get() {
            return getTag(javaClass) //牛逼特性来了,Kotlin可以在运行时获取当前的类。javaClass这个val字段存在于每个Class(类/接口/枚举)中
        }

    fun isLogable(): Boolean = true

    fun verbose(message: Any?){ //不建议在这里声明默认实现方法(除非继承类要重写),建议使用扩展方法,这样让接口保持清晰
        if (isLogable()) {
            println("[$tag][Verbose]:$message")
        }
    }
}

关键点我都在代码处写了出来了。

  1. javaClass这个是字段,在每个类/接口/枚举中都有这个字段,这个字段能在运行时获取当前类。

  2. 接口可以声明val字段,var字段是不允许的(因为接口是抽象的,不能存放实例对象,他不是类)。

  3. 接口中可以声明默认方法,这个特性和Java8中的是一样的,接口中的默认方法在实现类中可以选择重写也可以选择不重写(因为默认实现了嘛)。

  4. 对于与业务有关的默认方法建议用扩展方法实现。这样能保持接口干净

  5. 再看下扩展方法

inline fun<reified T:Any> Logger() = Logger(T::class.java)

最后附上代码如下,里面包含关键点的注释,大家可以放到copy到IDE中run一下看看。

package com.threshold.kotlin

interface Logger {
    val tag: String
        get() {
            return getTag(javaClass) //牛逼特性来了,Kotlin可以在运行时获取当前的类。javaClass这个val字段存在于每个Class(类/接口/枚举)中
        }

    fun isLogable(): Boolean = true

    fun verbose(message: Any?){ //不建议在这里声明默认实现方法(除非继承类要重写),建议使用扩展方法,这样让接口保持清晰
        if (isLogable()) {
            println("[$tag][Verbose]:$message")
        }
    }
}

fun Logger(clazz: Class<*>):Logger = object : Logger {
    override val tag: String
        get() = getTag(clazz)
}

inline fun<reified T:Any> Logger() = Logger(T::class.java)
/*
    复习下: inline 内联,可以提高程序执行效率,避免创建许多中间对象。
             reified 使具体化(翻译来的) 他必须和inline一起使用(不能inline的方法里传递的泛型对象是不能具体化的)
             还有点要注意,Kotlin的泛型方法中的尖括号必须紧跟着fun关键字后面,不能跟在方法名后面,
                熟悉C#或许会感觉很别扭,但是这个跟Java是一脉相连的,java要求的是在方法名之前要声明泛型。

fun testGeneric<T:Any>(){
    //编译错误.泛型必须紧跟着fun关键字后面。上面这种写法像是在使用的时候
}
 */

fun Logger.debug(message: Any?) {
    if (isLogable()) {
        println("[$tag][Debug]:$message")
    }
}

inline fun Logger.debug(message: () -> Any?){
    if (isLogable()) {
        println("[$tag][Debug]:${message()}")
    }
}

private fun getTag(clazz: Class<*>):String {
    val tag =  clazz.simpleName
    return if (tag.length < 23) {
        tag
    } else {
        tag.subSequence(0,23).toString()
    }
}

class LoggerTest1:Logger{
    override val tag: String
        get() =  "MyTag"

    override fun isLogable(): Boolean {
        return super.isLogable() //在Android中一般是根据Build中的Debug字段来判断是否需要输出日志
    }
    fun doSomething(){
        debug("Do something")
        verbose("log something too")
    }
}

class LogggrTest2{
    val logger = Logger(LogggrTest2::class.java) 
//注意这里的Logger(xx)其实是顶部方法,只不过他的方法名就是这个接口名。这个方法使用object关键词生成了一个匿名对象。注意他不是构造函数。

    fun doSomething(){
        logger.verbose("verbose something")
        logger.debug {
            "lazy debug string"+ 2 //This is only calculate when logable is true
        }
    }
}

class LoggerTest3{
    val logger = Logger<LoggerTest3>()

    fun doSomething(){
        logger.verbose("verbose logger something")
        logger.debug {
            "lazy debug message"
        }
        logger.debug("normal debug message")
    }
}

fun main(args:Array<String>): Unit {
    val loggerTest1 = LoggerTest1()
    loggerTest1.doSomething()

    val loggerTest2 = LogggrTest2()
    loggerTest2.doSomething()

    val loggerTest3 = LoggerTest3()
    loggerTest3.doSomething()

}

运行结果:

[MyTag][Debug]:Do something
[MyTag][Verbose]:log something too
[LogggrTest2][Verbose]:verbose something
[LogggrTest2][Debug]:lazy debug string2
[LoggerTest3][Verbose]:verbose logger something
[LoggerTest3][Debug]:lazy debug message
[LoggerTest3][Debug]:normal debug message

Process finished with exit code 0


关注我的公众号.jpg
上一篇 下一篇

猜你喜欢

热点阅读