2017-09-18 2 views
0

Ich habe eine Klasse Stealth Implementierung der Schnittstelle Skill und eine Klasse SoundlessMovement die Implementierung der Schnittstelle Mastery. Jetzt möchte ich die Meisterschaft SoundlessMovement der SkillStealth hinzufügen, während die Mastery durch die Skill unterstützt wird.Ist es möglich, den Typ einer Liste auf eine Implementierung einer Schnittstelle in Kotlin zu beschränken?

Ich möchte so etwas wie dieses (Pseudo-Kotlin) tun:

interface Skill { 
    val masteries: List<Mastery<Skill>> // Mastery linked to type Skill 
} 

und

interface Mastery<Skill> { // Every Mastery must be compatible with only one Skill 
    val masteryName: String 
} 

mit Implementierungen:

class Stealth : Skill { 
    override val masteries: ArrayList<Mastery<Stealth>() // Any Mastery bound to Stealth 
} 

und

class SoundlessMovement : Mastery<Stealth> { // Is a Mastery compatible with Stealth 
    override val masteryName = "Soundless Movement" 
} 

Ziel ist es, sicherzustellen, dass einer Fertigkeit nur kompatible Meisterschaften hinzugefügt werden können. Ist so etwas überhaupt möglich? Und wenn ja, wie könnte es in Kotlin umgesetzt werden?

+0

Ich bin mir bewusst, dass der Titel der Frage schlecht ist. Ich habe einfach keine Ahnung, wie ich das Problem besser beschreiben könnte. – zoku

+0

Ihr Klassendesign ist nicht verständlich. Warum "Mastery" braucht einen generischen Parameter, aber nicht? Warum hält Skill eine Listenreferenz für seine Klasse? Können Sie erklären, was Sie erreichen wollen und Ihre Klassenbeziehung? – Joshua

+0

@Joshua Die Struktur ist vereinfacht, um nur den problematischen Teil des Codes zu zeigen. Vereinfacht ausgedrückt versuche ich eine Klasse zu haben, die eine Schnittstelle implementiert, die eine Liste mit dem Typ einer anderen Klasse enthält, die eine andere Schnittstelle implementiert und an die erste Klasse gebunden ist. Ziel ist es, das Vermischen von Fertigkeiten und Meisterschaften zu verhindern, indem jede Meisterschaft an eine bestimmte Fähigkeit gebunden wird. Also ist Pelochos Antwort genau das, was ich versuchte zu tun. – zoku

Antwort

3

Ich weiß nicht, ob ich verstehe Sie wirklich, aber ich denke, dass dieses Stück Code Ihr Problem löst:

interface Mastery<Skill> { 
    val masteryName: String 
} 

interface Skill<Self : Skill<Self>> {        // forces every Skill to bound to itself 
    val masteries: List<Mastery<Self>> 
} 

abstract class Stealth : Skill<Stealth> { 
    override val masteries = ArrayList<Mastery<Stealth>>() 
} 

class SoundlessMovement : Mastery<Stealth> {   // a Stealth mastery 
    override val masteryName = "Soundless Movement" 
} 

class SoundlessMovement2 : Mastery<Stealth> {  // another Stealth mastery 
    override val masteryName = "Soundless Movement 2" 
} 

abstract class Archery : Skill<Archery> {   
    override val masteries = ArrayList<Mastery<Archery>>() 
} 

class SureShot : Mastery<Archery> {     // some other mastery 
    override val masteryName = "Sure shot 2" 
} 

fun main(args: Array<String>) { 

    var list = ArrayList<Mastery<Stealth>>() 

    list.add(SoundlessMovement())   // compiles 
    list.add(SoundlessMovement2())   // compiles 
    list.add(SureShot())      // Doesn't compile 
} 

Der Schlüssel hier ist Skill<Self> zu verwenden, um die aktuellen Implementierungen gebunden. Beachten Sie auch, dass ich class Stealth ... zu geändert habe, da Sie sind, die den Mastery-Typ definieren. Eine weitere Option könnte Kotlin's sealed class

Beachten Sie, dass Selfist nicht ein reserviertes Wort noch etwas ähnliches werden. Der Code funktioniert auch, wenn Sie ihn nur in T ändern. Ich entschied mich, Self nur zu verwenden, um Sie darauf aufmerksam zu machen, welchen Typ Sie dort setzen sollten

+0

Ah! Das macht Sinn. Es erklärt auch, warum ich noch nie davon gehört habe. Es ist besser lesbar als 'Foo >' obwohl. Jetzt, wo ich weiß, dass "Self" kein Schlüsselwort ist, verstehe ich auch, was der Code tut. Es ist noch einfacher als ich dachte. – zoku

Verwandte Themen