2016-08-18 5 views
3

フィールドには複数のフィールドがあり、フォームで使用され、いずれかのフィールドが入力されている場合はメソッドを返すようにする必要があります。true連合型/拡張インタフェース

私はすべてのクラスのためにこれを書き換える必要はありませんので、私は、現時点では、このようにそれをやっている:

data class Order(var consumer: String, var pdfs: List<URI>): Form { 

    override val isEmpty(): Boolean 
     get() = checkEmpty(consumer, pdfs) 
} 

data class SomethingElse(var str: String, var set: Set<String>): Form { 

    override val isEmpty(): Boolean 
     get() = checkEmpty(str, set) 
} 


interface Form { 
    val isEmpty: Boolean 

    fun <T> checkEmpty(vararg fields: T): Boolean { 
     for (f in fields) { 
      when (f) { 
       is Collection<*> -> if (!f.isEmpty()) return false 
       is CharSequence -> if (!f.isBlank()) return false 
      } 
     } 
     return true; 
    } 
} 

これは明らかに非常にきれいでも、タイプセーフではありません。

どのような種類のFieldタイプにすべてのプロパティを抽象化せずに、これを行うより慣用な方法はありますか?

明確化:私が探している彼らがしている場合伝えるために、すべての許可されたタイプ(StringIntListSet)し、それぞれの機能を提供することにより、例えば、網羅whenを取得する方法である空の。メソッドisEmptyFormFieldを持つ「拡張インタフェース」と同様です。

答えて

2

isEmpty/isBlank/isZero/etcを確認している場合は、おそらく一般的なcheckEmpty関数などは必要ありません。:あなたが実際にしている場合

data class Order(var consumer: String, var pdfs: List<URI>) : Form { 
    override val isEmpty: Boolean 
     get() = consumer.isEmpty() && pdfs.isEmpty() 
} 

data class SomethingElse(var str: String, var set: Set<String>) : Form { 
    override val isEmpty: Boolean 
     get() = str.isEmpty() && set.isEmpty() 
} 

interface Form { 
    val isEmpty: Boolean 
} 

しかし、私は「Field型のいくつかの種類にすべてのプロパティを抽象化すると、」あなただけはありませんしたい正確に何であると信じて追加した解明に基づいて、その後、もう少し複雑な何かをFieldインスタンスに各data classの一部にすることではなく、必要なときにそれらのリストを作成します。

data class Order(var consumer: String, var pdfs: List<URI>) : Form { 
    override val fields: List<Field<*>> 
     get() = listOf(consumer.toField(), pdfs.toField()) 
} 

data class SomethingElse(var str: String, var set: Set<String>) : Form { 
    override val fields: List<Field<*>> 
     get() = listOf(str.toField(), set.toField()) 
} 

interface Form { 
    val isEmpty: Boolean 
     get() = fields.all(Field<*>::isEmpty) 

    val fields: List<Field<*>> 
} 

fun String.toField(): Field<String> = StringField(this) 
fun <C : Collection<*>> C.toField(): Field<C> = CollectionField(this) 

interface Field<out T> { 
    val value: T 
    val isEmpty: Boolean 
} 

data class StringField(override val value: String) : Field<String> { 
    override val isEmpty: Boolean 
     get() = value.isEmpty() 
} 

data class CollectionField<out C : Collection<*>>(override val value: C) : Field<C> { 
    override val isEmpty: Boolean 
     get() = value.isEmpty() 
} 

これは、など、あなたは型の安全性をごdata classコンポーネントを変更することなく、与え、あなたは「0123網羅取得することができます"。

+0

まだ完全に満足していないので、非常に冗長ですが、私はこの答えを受け入れるつもりです。ありがとう。 –

3

これはちょっとハッキリですが、うまくいくはずです。 すべてdata classは、各コンストラクタパラメータごとにメソッドのセットを作成します。 componentN()Nは、コンストラクタパラメータを示す1から始まる番号です)です。

このようなメソッドをインターフェイスに配置して、data classを暗黙的に実装することができます。

data class Order(var consumer: String, var pdfs: List) : Form 

data class SomethingElse(var str: String, var set: Set) : Form 

interface Form { 
    val isEmpty: Boolean 
     get() = checkEmpty(component1(), component2()) 

    fun checkEmpty(vararg fields: T): Boolean { 
     for (f in fields) { 
      when (f) { 
       is Collection -> if (!f.isEmpty()) return false 
       is CharSequence -> if (!f.isBlank()) return false 
      } 
     } 
     return true; 
    } 

    fun component1(): Any? = null 
    fun component2(): Any? = null 
} 

ます。また、...などfun component3(): Any? = nullを追加することができ、よりその2つのdata class(例えばNullObjectパターン内のフィールドまたはIのようnullの直接checkEmpty()方法で

を処理してケースを処理するために:。下の例を参照してください。それはちょっとハックだが、多分あなたのために働くだろう、と述べた

+0

いいアイデア。また、nullを使用できるcomponentNメソッドを作成する代わりに、リフレクションを使用してコンポーネント関数をリストすることもできます。 – mfulton26

+0

これは良いアイデアですが、私が探していたのは網羅的な「いつ」を得るための方法でした。例えば。任意の型が "空"であるかどうかを知る方法の機能を提供する。文字列の場合は 'isBlank()'、コレクションの場合は 'isEmpty()')... –

1

あなたが「未指定」を意味するnullを使用することができます。

data class Order(var consumer: String?, var pdfs: List<URI>?) : Form { 
    override val isEmpty: Boolean 
     get() = checkEmpty(consumer, pdfs) 
} 

data class SomethingElse(var str: String?, var set: Set<String>?) : Form { 
    override val isEmpty: Boolean 
     get() = checkEmpty(str, set) 
} 

interface Form { 
    val isEmpty: Boolean 
    fun <T> checkEmpty(vararg fields: T): Boolean = fields.all { field -> field == null } 
} 

ここでの考え方は、など、JavaでOptional<T>のものと同じですが、余分なオブジェクトなしで

あなたは今についてnull safetyを心配する必要はなく、自分のフィールドは、その後不在/空の概念を持っていることを意味している場合これは適切と思われます(UsingAndAvoidingNullExplained · google/guava Wiki)。

+0

このようにして、これらのクラスを使用するコードではnull安全性を失います。空の時に 'List'sをnullに設定することを覚えておく必要があります。 –

関連する問題