首页 文章

如何在Kotlin中实现模板方法设计模式?

提问于
浏览
5

考虑一下问题:

我们有一个带有抽象方法的 Base 类 . 现在,我们希望强制执行此方法的每个覆盖都将执行一些参数检查或其他一些苦差事 . 我们希望这个参数检查在所有覆盖中都是相同的 . 一种解决方案是将此行为包装在一个非抽象方法中,该方法调用一个抽象方法:

abstract class Base
{
    fun computeSomething(argument: Int): Int
    {
        require(argument > 0) // Some intricate checking
        return execute(argument)
    }

    // Pure functionality, assuming correct arguments
    // Ideally, this would be private. 
    protected abstract fun execute(validArgument: Int): Int
}

class Derived1: Base()
{
    override fun execute(validArgument: Int): Int =
        validArgument * validArgument
}

class Derived2: Base()
{
    override fun execute(validArgument: Int): Int =
        validArgument * validArgument * validArgument
}


fun main(args: Array<String>)
{
    val d = Derived1()
    println(d.computeSomething(23))
}

我想 Base::execute 是私有的,这样没有 Base 的子类可以在不检查其参数的情况下偶然调用它 . 不幸的是,这是不可能的:

错误:(9,5)Kotlin:修饰符'private'与'abstract'不兼容

Kotlin的 protected 比Java的 protected 更好,因为它使该函数只能被子类访问,但理想情况仍然是 private .

那么有没有一种正确的方法来实现这种模式?另外,出于好奇, privateabstract 是否是故意选择语言设计的不兼容性?

2 回答

  • 2

    对函数进行重写没有意义,但是不能从该类调用 . 通过覆盖该函数,您可以拥有它的实现,因此可以调用它 .

    您可以通过从派生类中分离执行逻辑来完成您想要的任务,这可以通过以下几种方式完成:

    • 你可以使用lambda,并将其传递给 Base 的构造函数

    • 您可以创建一个处理执行逻辑的接口实现

    通过将它们传递给构造函数中的 Base 类,您将其所有权转移到该类 .

  • 1

    您可以使它们传递将检查值的对象,如果他们想要调用此方法 . 例

    abstract class Base
    {
        fun computeSomething(argument: Int): Int
        {
            return execute(ValueCheck(argument))
        }
    
        protected abstract fun execute(validArgument: ValueCheck)
    
        protected class ValueCheck(a: Int)
        {
            private val value = checkValue(a)
    
            private fun checkValue(argument: Int): Int
            {
                require(argument > 0)
                return argument
            }
    
            fun get() = value
        }
    }
    

    当派生类想要调用execute时,它必须在创建实例时传递检查值的对象

相关问题