bugfix> interface > 投稿

デフォルトのゲッターを持つ多くの不変のプロパティを提供するインターフェイスがあるとします

interface Repository {
    val name : String
    val pattern : String
        get() = "foo/bar/baz"
    var url : String
        get() = "http://mycompanyrepo.com/$name"
    fun add() {
        TODO("do something interesting here")
    } 
}

現在、デフォルトのほとんどを使用する具体的な実装がいくつかあります。ただし、 ConfigurableRepository も提供したいこれにより、他のユーザーパラメーターに基づいて、実行時にこれを構成する他のプロジェクトの柔軟性が高まります。

オプションのパラメーターを持つプライマリコンストラクターを作成するにはどうすればよいですか?

私は次のものに沿って何かを望んでいました:

class ConfigurableRepo(var name, var pattern, var url) {
   ...
}

明確化のために編集

ここでの目的は、名前付きパラメーターがオプションであるプライマリコンストラクターの動作を使用することです。より具体的には、 namepattern 、および url コンストラクターを呼び出す人はすべてオプションであり、デフォルトでインターフェースのゲッターになります。しかし、私は明らかにKotlin interface を強制しようとしていますこのモデルに合わせると、おそらく私は最終的にここでスーパーにアクセスできないので、おそらくnoob Kotlinユーザーの間違いです。

からクラスのドキュメント  

In fact, for declaring properties and initializing them from the primary constructor, Kotlin has a concise syntax:

class Person(val firstName: String, val lastName: String, var age: Int) {      
    // ...
}

私はこれがスーパータイプのメンバーを隠し、 override を必要とするというエラーを受け取っているようです修飾子。スーパータイプをオーバーライドしてからデフォルトを提供しようとすると、このコンテキストではスーパータイプにアクセスできないと文句を言います。

これは、mutableのセカンダリコンストラクターでのみ実行できますか   値?

また、従来の設定をサポートするインターフェースを提供するためのより良い方法についての提案/フィードバックも受け付けています。最も重要な側面は、インターフェイスが常に規則のデフォルトを提供することです。または、もっと簡単に言えば:

もっと良い方法はありますか?    

回答 4 件
  • ご覧ください https://kotlinlang.org/docs/reference/visibility-modifiers.html

    特に、クラスとインターフェースに関する2番目の段落。

    これらの例から、もし可能であれば、インターフェースの代わりに基本クラスを使用することが提案されます。これは次のようになります。

      open class DefaultRepo {
            protected open val name = "foo/bar/baz"
            protected open val pattern = "foo/bar/baz"
            protected open val url = "http://mycompanyrepo.com/$name"
            open fun add() {
                TODO("do something interesting here")
            }
        }
        class RenamedRepo(newName: String): DefaultRepo() {
            override val name = newName
        }
        class ConfigurableRepo(n: String, p: String, u: String): DefaultRepo() {
            override val name = n
            override val pattern = p
            override val url = u
            override fun add() {
            }
        }
    
    

  • 次のような抽象クラスを使用します。

    abstract class Repository {
        open val name = "default"
        open val pattern = "default"
        open val url = "default"
    }
    // example: only override name
    class RepoWithDifferentName(
        override val name: String
    ): Repository() {
       // ...
    }
    
    

  • var でそれを行う方法を見つけたので s、ここにあなたの質問からの正確なインターフェースの答えがあります。

    class ConfigurableRepo(
            private var _name: String,
            private var _pattern: String,
            private var _url: String) : Repository 
    {
        override val name get () = _name
        override val pattern get () = _pattern
        override var url
            get () = _url
            set (u: String) { _url = u }
    }
    
    

  • 次のようなデフォルトコンストラクターのパラメーターにデフォルト値を設定する場合(擬似コード、コンパイルしない):

    class ConfigurableRepo(
        override var name, 
        override var pattern = super.pattern, 
        override var url = super.url
    ) {
        ...
    }
    
    

    次に、目的のデフォルト値をメソッド宣言で表現できない場合に常に使用できる「null as default pattern」を使用します。あなたの場合、次のようになります:

    class ConfigurableRepo (
            override val name: String,
            _url: String? = null,
            _pattern: String? = null
    ): Repository {
        override val pattern = _pattern ?: super.pattern
        override var url = _url ?: super.url
        // ... more code ...
    }
    
    

    ご覧のとおり、このトリックは val で動作します  同様に var  プロパティとフィールド。プロパティ name  インターフェイスにデフォルト値を持たないものは、このクラスの単純なフィールドで実装されます。

あなたの答え