Java 인스턴스를 대체 하시겠습니까?


10

그래서 저는 실제 (학업 프로젝트를 제외하고) 프로그래밍에 익숙하지 않으며 instanceof특정 객체가 어떤 클래스인지 결정하는 데 사용하는 것이 좋지 않다는 많은 게시물을 보았습니다 .

내 상황은 기본 제품 클래스, 그중 하나를 확장하고 다른 하나를 확장하는 세 가지 클래스가 있다는 것입니다. 이것들은 모두 데이터베이스의 동일한 테이블에 저장되어 있으며 각각의 메소드를 사용하여 데이터를 가져 오는 코드가 있습니다.

이 방법으로 해결하는 가장 좋은 방법은 무엇입니까? 다형성에 대한 몇 가지를 읽었지만 문제를 해결하는 예를 찾을 수 없습니다. 그들은 일반적으로 다른 객체에서 다른 것을 가져와야하기 때문에 작동하지 않는 방법을 대체합니다.

이 작업을 수행하는 더 좋은 방법이 instanceof있습니까? 아니면 객체에 특정한 필드를 얻기 위해 반사 또는 일종의 반사를 사용하고 있습니까?


10
키워드 instanceof가 잘못된 것은 아닙니다 . 객체의 클래스를 찾으려고 시도하는 것이 일반적으로 문제입니다. 항상 틀린 것은 아니지만 아마도 귀하의 경우에는 그렇습니다. 어쩌면 당신이 달성하려고하는 것을 말하면 다형성을 사용하는 솔루션을 제안 할 수 있습니다.
Andres F.

2
각 클래스에는 고유 한 데이터가 있습니다. 이들로부터 특정 데이터를 가져오고 싶습니다. 나는 내가 가진 도움으로 대답을 깨달았다 고 생각합니다. 라는 방법 비슷해 getSpecifics()각 클래스에 데이터의 특정 반환과 함께, 각각 다르게 구현?
토마스 미첼

답변:


16

instanceof권장하지 않는 이유 는 OOP가 아니기 때문 입니다.

객체의 호출자 / 사용자가 변수가 선언 된 변수의 유형을 넘어서는 어떤 구체적인 클래스인지 알 필요가 없습니다.

서브 클래스에서 다른 동작이 필요한 경우 메소드를 추가하고 다르게 구현하십시오.


1
따라서 getSpecifics()각 클래스의 특정 정보를 반환하는 각 클래스 의 메소드 (또는 이와 유사한 것). 이것이 최선의 접근입니까?
Thomas Mitchell

@Schmooo 클래스 트리 내에서 공통 기능이 존재하는 위치와 각 수준에서 어떤 계약이 존재하는지 고려해야합니다.

3
그러나 객체가 레이어를 교차하고 유형 정보가 손실되는 경우는 어떻습니까? 예를 들어 List. 나는 그것을 취하는 객체에 전달합니다 Iterable. 이제 두 번째 객체 List는 최적화를 위해 또는 Iterable훨씬 더 느린 세 번째 객체로 전달합니다 . 두 번째는 목록이라는 것을 알지 못하지만 세 번째는 알고 싶습니다. 세 번째 객체가 instanceof를 확인하여 최적화를 적용 할 수 있는지 확인해서는 안됩니까? 예를 들어 구아바 FluentIterable를 참조하십시오 .
Laurent Bourgault-Roy

1
항상 클래스에 메소드를 추가 해야하는 것은 아닙니다. 예를 들어, 일부 코드는 예외가 발생하고 유형에 따라 무언가를 수행해야합니다. 예를 들어, 보고서를 작성하거나 오류에서 복구 할 수있는 작업을 수행하십시오. 이러한 종류의 기능은 예외에 맞지 않습니다. 또는 클래스가 외부 라이브러리에서 온 경우 이러한 클래스를 수정할 수있는 방법조차 없습니다. 이 경우에 의존하는 것이 절대적으로 유효하다고 생각합니다 instanceof.
Malcolm

9

instanceof 반드시 나쁜 것은 아니지만, 꼭 봐야 할 것입니다.

그것이 올바르게 작동하는 예는 기본 유형의 컬렉션을 가져오고 하위 유형의 컬렉션 만 원하는 곳입니다. 네트워크 주소를 가져 NetworkInterface.getNetworkInterfaces()오면 InetAddress 개체의 컬렉션이있는 NetworkInterface 개체가 반환되는데, 그 중 일부는 Inet4Address이고 일부는 Inet6Address입니다. Inet4Address 객체에 대한 컬렉션을 필터링하려면 instanceof를 사용해야합니다.

원래 게시물에 설명되어있는 상황에는 기본 클래스, 기본 클래스를 확장하는 클래스 및 확장 클래스를 확장하는 클래스가 있습니다. 완전한 정보를 제공하지는 않지만 이상적인 디자인보다 약간 낮은 토대를 가지고있는 것 같습니다.

기본 클래스를 리턴 할 때 (이전 버전의 스펙 간 이전 버전과의 호환성) 그렇게 설계되지 않은 이유가 없으면 기본 유형을 들여다 보지 않아야합니다. 세트가 반환되면 세트를 받고있는 것입니다. 이를 통해 개발자는 나중에 마음을 바꾸어 더 구체적인 유형 (SortedSet)을 반환하거나 기본 유형 (HashSet을 TreeSet으로)을 변경하지 않고 변경할 수 있습니다.

유형이 구분되지 않는 더 나은 클래스 모델을 만들 수 있는지 확인하기 위해 객체가 어떻게 구성되고 부모가되는지에 대한 디자인을 다시 고려하십시오.


인터페이스가 isOfType(SomeEnum.IPv4)메소드를 지정 하도록하는 것이 콘크리트 유형을 통해 검사하는 것보다 이러한 품질을 필터링하는 더 좋은 방법 일 수 있습니다 instanceof. 나중에 IPv4 구현 클래스를 분할하려면 어떻게해야합니까? 이것이 항상 더 좋은 것은 아니지만 고려할 사항입니다.
Steven Schlansker

@StevenSchlansker 특정 클래스에서 작동 할 수 있습니다. 그러나 캐스트가 가능한지 확인하기 위해 구체적 유형을 검사해야하는 경우 (또는 예외를 캐스트하고 예외를 잡아야하는 경우) Inet6Address는 InetAddress보다 많은 메소드를 구현합니다. 인터페이스 (패키지 또는 클래스 로더의 모든 클래스를 열거하는 열거 형)와 함께 작동하기가 어려울 수 있으므로 메소드를 직접 구현해야합니다 (또는 Object의 일부 리플렉션 코드). 방법을 고려하십시오 (o instanceof Serializable) || (o instanceof Externalizable). instanceof가 대안보다 낫습니다

1

getClass () 메소드를 사용할 수 있습니다.

세 개의 다른 수업이 필요하십니까? 어쩌면 내부에 스위치가있는 클래스가 더 좋을까요?


7
getClassinstanceof공유 단점. 다형성은 적합 할 때 둘 다보다 낫고 OP의 사용 사례에 맞지 않는 것으로 보입니다.

나는 당신의 첫 문장에 반대되는 것이 없습니다. 그러나 두 번째는-죄송합니다, 당신은 전혀 무엇을 의미하는지 이해할 수 없습니다.
Gangnus

1
와 함께 getClass도 여전히 같은 문제를 공유하지 instanceof않습니까? 나는 여전히 내가 가지고있는 것을 찾아서 일련의 함수를 호출해야합니다. 이상적으로는 해당 객체에 캐스트 할 필요없이 해당 클래스에 특정한 데이터를 반환하는 메소드를 원합니다.
토마스 미첼

나는 종종 더 나은 선택이기 때문에 다형성을 무시하는 것에 대해 불평하고 있습니다. 문제의 유스 케이스가 다형성으로 수행 될 수 있다고 확신하므로 어느 것도 사용할 필요가 없습니다. (그 외에 다른 사람의 답변을 재현하는 것은 좋지 않습니다.)

2
@ Gangus 나는 이것을 "공격"이라고 생각하지 않는다. 하지만 뭐든지 아니요, 질문은 "다른 무엇을 사용할 수 있는가"가 아니라 "이를 수행하는 더 좋은 방법이 있습니까"입니다. 당신이 주장 할 않는 한 getClass그것을 할 수있는 더 좋은 방법은 ;-) 답변의 대부분을 차지 어떤 사업이 없다,이다

1

일반적으로 무언가의 유형을 알고 싶다면 객체 구조를 잘못 구현했음을 의미합니다. 이 시간의 대부분은 LSP 를 위반하게 됩니다.

그러나 동적 디스패치를 ​​수행하고 많은 보일러 플레이트 코드를 저장하고 객체 구조를 미래에 보장하는 방법을 원할 때가 있습니다. C #은 프레임 워크의 최신 설치에서 동적 키워드를 제공하지만 Java에 대해서는 여전히 비슷한 것이 없습니다.

즉, instanceof는 상속을 올바르게 지원하므로 클래스를 비교하는 것보다 일반적으로 좋습니다. isAssignableFrom과 같은 메소드 및 reflexion API의 다른 메소드를 사용할 수도 있습니다. 동적 디스패치와 같은 것을 구현하려면 리플렉션 API를 통해 수행 할 수 있지만 조심해야합니다. 가능하면 앱의 객체 구조와 desing을 수정하는 것이 이상적입니다.

도움이 되었기를 바랍니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.