2016-08-18 3 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 유형으로 추상화하지 않고이 일을하는 관용적 인 방법은 무엇입니까?

명확한 설명 : 내가 찾고가 있다면 알려 허용 된 모든 종류의 (String, Int, List, Set) 및 각각의 기능을 제공하여, 예를 들어, 철저한 when을 얻을 수있는 방법이다 빈. 메서드가 isEmptyFormField 인 "확장 인터페이스"와 같습니다.

답변

2

/isEmpty/isBlank/isZero/등을 확인하는 것입니다. 그렇다면 일반 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 타입의 일종으로 모든 속성을 추출하는 것은"그냥하지 않는 원하는 정확히 무엇이라고 생각은 당신이 머무르는 설명에 따라 다음 좀 더 복잡한 일을 할 필요한 경우 각 data classField 인스턴스 부분을 대신 이들의 목록을 만들 :

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 구성 요소를 변경하지 않고 제공하고 "철저한 얻을 수 있습니다".

+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

좋은 아이디어. nullable componentN 메소드를 작성하는 대신 리플렉션을 사용하여 컴포넌트 함수를 나열 할 수도 있습니다. – mfulton26

+0

이것은 좋은 생각이지만, 내가 찾고 있었던 것은 철저한 '언제'를 얻을 수있는 방법이었습니다. 예 : 임의의 유형이 "비어 있음"인지를 판별하는 기능을 제공합니다. (isBlank() String, Collection을위한 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 } 
} 
여기 아이디어는 자바하지만 여분의 객체가없는 Optional<T>의 것과 동일

이제 약 null safety하지만 걱정해야

당신의 필드는 다음 결석/빈의 개념이 의미하는 경우 이것은 적절하다고 (UsingAndAvoidingNullExplained · google/guava Wiki).

+0

그런 식으로이 클래스를 사용하는 코드에서 null-safety를 많이 잃게됩니다. 비어있을 때'List's를 null로 설정하는 것을 잊지 말아야합니다. –