2016-12-28 1 views
1

현재 격자 모양의 구조에서 작업을 처리 할 수있는 추상 코드로 작업하고 있습니다. 구체적인 방법 대신 lambda 표현식을 허용하고 그리드 요소 간의 방향성 관계에 기반한 기능을 제공하는 프레임 워크를 개발하려고 시도했습니다. 이러한 메서드에 제네릭 형식을 반환하려고 할 때 문제가 발생했습니다.일반 반환 형식 및 람다 함수 인수

나는 특정 방향의 그리드 요소를 찾는 람다 함수를 허용하는 작업 방법과 각 요소에 대해 특정 방법을 실행하는 소비자를 가지고있다. 대신 요소-찾는 기능이 메소드가 호출 될 때마다 시간을 통과해야하는

public static <E> void forEachClockwise(Direction d, Function<Direction, ? extends E> f, Consumer<? super E> c){ 
    /*For each of the orthogonal directions, in order:*/ 
     c.accept(f.apply(d)); 
    /*end For*/ 

} 

, 나는 그것을 선언과 같은 기능을 갖는 인터페이스 '직교'를 가지고 있고,에 forEachClockwise 방법을 과부하가 좋은 것입니다 결정 이 인터페이스의 요소를 받아들입니다.

public static <O extends Orthogonal> void forEachClockwise(Direction d, O center, Consumer<O> c){ 
    forEachClockwise(d, center::findNextByDirection, c); 
} 

여기서는 제네릭을 사용했으며 Consumer 메서드가 캐스팅하지 않고 그리드 요소의 필드에 액세스 할 수 있도록 선언했습니다. 직교 인터페이스와 내가 만든 테스트 클래스가 몇 가지 다른 것들을 시도 함에도 불구하고 경고없이 그리고 캐스트없이 컴파일되지 않았기 때문에 이것은 잘못된 설계 선택이었다고 우려하고 있습니다. 내가 해봤 findNextByDirection의

public interface Orthogonal { 
    public <E extends Orthogonal> E findNextByDirection(Direction a); 
} 

두 '유효'구현은 다음과 같습니다

/* in Coordinate implements Orthogonal: */ 
@Override 
public <E extends Orthogonal> E findNextByDirection(Direction a) { 
    return (E) (/*The proper Coordinate*/); 
} 

그리고

최적
@Override 
public Coordinate findNextByDirection(Direction a) { 
    return /*The proper Coordinate*/; 
} 
//Warning on return type declaration: 
/*Type safety: The return type Element for findNextByDirection(Direction) from the type Element needs unchecked conversion to conform to E from the type Orthogonal*/ 

, 나는 방법을하고 싶은 그 forEachClockwise (그리고 다른 메소드)는 받아 들일 수 있습니다. 이것은 캐스팅하지 않고 호출하는 동일한 클래스의 요소를 리턴합니다. 좌표의 findNextByDirection은 좌표를 반환해야하며 주소는 주소를 반환해야하고 셀은 셀을 반환해야합니다. 기타 질문 및 답변 일반 반환 형식을 사용하여 메서드를 만드는 방법에 대해 알아 보았지만 찾지 못했습니다. 이러한 종류의 메서드를 람다 매개 변수로 사용하는 방법에 대한 힌트.

아직 시도하지 않은 몇 가지 사항은 직사각형으로 정의 된 일부 메서드로 forEachClockwise 메서드를 호출하거나 인수로 직사각형 및 방향의 일부를 받아들이는 새로운 findByDirection 메서드를 만드는 것입니다. 내가 시도한 것처럼. 인터페이스를 고유 한 제네릭 형식으로 지정하는 것이 다른 접근 방식이지만 인터페이스가 "MyClass가 직교를 구현"하는 것으로 모든 직교 클래스를 선언하는 것은 분명히 잘못되었고 목적이 없습니다.

이 인터페이스를 완전히 디자인 했습니까? 제네릭이 무언가를하기를 기대하면서 처음부터 틀렸던가? 아니면 클래스를 가져 와서 올바른 메소드를 호출하고 그 타입의 요소를 일반적으로 반환하는 간단한 방법이 있습니까?

전체 코드 :

package test; 

import java.util.function.Consumer; 
import java.util.function.Function; 


public enum Direction { 
    NORTH, EAST, SOUTH, WEST; 

    public static <O extends Orthogonal> void forEachClockwise(Direction d, O center, Consumer<O> c){ 
     forEachClockwise(d, center::findNextByDirection, c); 
    } 

    public static <X> void forEachClockwise(Direction d, Function<Direction, ? extends X> f, Consumer<? super X> c){ 
     c.accept(f.apply(d)); 
     forEachExcept(d, f, c); 
    } 

    public static <X> void forEachExcept(Direction d, Function<Direction, ? extends X> f, Consumer<? super X> c){ 
     for(int i=0; i<3; i++){ 
      d = Direction.getClockwise(d); 
      c.accept(f.apply(d)); 
     } 
    } 

    public static Direction getClockwise(Direction d){ 
     switch(d){ 
     case EAST: 
      return SOUTH; 
     case NORTH: 
      return EAST; 
     case SOUTH: 
      return WEST; 
     case WEST: 
      return NORTH; 
     default: 
      return null; 
     } 
    } 

} 

interface Orthogonal { 
    public <E extends Orthogonal> E findNextByDirection(Direction a); 
} 






class Coordinate implements Orthogonal{ 

    int x; 
    int y; 

    public Coordinate(int x, int y){ 
     this.x = x; 
     this.y = y; 
    } 

    public int getX(){ 
     return x; 
    } 

    public int getY() { 
     return y; 
    } 


    @Override //Warning on "Coordinate" below. Compiler suggests writing 
       //entire <E extends Orthogonal> method signature 
    public Coordinate findNextByDirection(Direction a) { 
     switch(a){ 
      case NORTH: 
       return new Coordinate(x+1, y); 
      case SOUTH: 
       return new Coordinate(x-1, y); 
      case EAST: 
       return new Coordinate(x, y+1); 
      case WEST: 
       return new Coordinate(x, y-1); 
      default: 
       return null; 
     } 
    } 
} 
+0

(경고와 함께) 컴파일하는 예제 전체를 만들면 도움이 될 것입니다. 예를 들어,이 직교의 구현은 경고없이'public class Element is Orgogonal { @Override public element findNextByDirection (Direction a) { return this; } } ' – assylias

+0

반환 형식 선언에 해당 스 니펫이 경고 메시지와 함께 컴파일되지 않습니다. Element : "형식 안전 : 형식 요소에서 findNextByDirection (Direction)의 반환 형식 요소에 E를 준수하는 검사되지 않은 변환이 필요합니다. Orthogonal 유형 " –

+0

(직교가 아닌 요소를 반환하는) 메소드 서명을 복사 했습니까? – assylias

답변

0

나의 이해는 당신의 findNextByDirection 방법에서, 당신은 포함하는 클래스와 같은 타입을 반환해야한다는 것입니다. 따라서 좌표 예제에서 좌표를 반환해야합니다.그런 경우에는

, 당신은 제네릭과 함께 한 단계 더 갈 수

interface Orthogonal<E extends Orthogonal<E>> { 
    public E findNextByDirection(Direction a); 
} 
class Coordinate implements Orthogonal<Coordinate> { 
    //rest is the same 
    //you should not have any warnings left 
} 

public static <O extends Orthogonal<O>> void forEachClockwise2(Direction d, O center, Consumer<O> c){ 
    forEachClockwise(d, center::findNextByDirection, c); 
} 

참고 : 두 forEachClockwise 방법은 충돌 (같은 원시 서명)가 그래서 나는 forEachClockwise2에 그 중 하나의 이름을 변경했다.

2

잠시 동안 Orthogonal-CoordinateArea을 구현하는 클래스가 있다고 가정 해 봅시다.

public <E extends Orthogonal> E findNextByDirection(Direction a); 

여기서 선언 한 것은 템플릿 처리 된 방법입니다. 선언문은 기본적으로 다음과 같이 말합니다. "특정 컨텍스트에서이 메서드는 항상 예상 된 형식을 반환합니다. 결과를 Coordinate 변수에 할당하면 메서드는 Coordinate을 반환하고 Area이면 Area을 반환하고 등등 - 한 어떤 것으로 예상된다하는 것은 당신이 public Coordinate findNextByDirection(Direction a)Coordinate에 그것을 구현하려고 할 때, 그러나 Orthogonal "

를 구현하는 유형입니다, 당신은 더 이상 주어진 상황에서 예상되는 어떤 반환을 약속하지 않습니다 - 당신을 이제 적으로 Coordinate을 반환함으로써 인터페이스에서 선언 된 계약을 위반하게됩니다. 더욱 심하다고 생각한다면 처음에는 계약을 실제로 만족시킬 방법이 없었습니다.

인터페이스 일반 (Orthogonal<E>)을 선언하고 메서드 선언에서 <E extends Orthogonal>을 삭제하십시오.

"뚜렷하게 잘못된"것으로 나타나는 class Coordinate implements Orthogonal<Coordinate> 선언 인 경우에는 안됩니다. 이는 일반적인 방법으로 SDK 자체에서 광범위하게 사용됩니다 (예를 들어 Comparable 참조).

findNextByDirectionOrthogonal을 반환해야하는 경우 반환 유형을 Orthogonal<E>으로 지정할 수 있습니다. Coordinate에 메서드를 구현하려면 public Coordinate findNextByDirection(Direction a)으로 Java의 유형 공분산으로 인해 경고가 표시되지 않아야합니다.

+0

"여전히 나쁘지 만 생각하면 처음부터 그 계약을 실제로 만족시킬 방법이 없습니다." 항상'null'을 반환하지 않는 한 :) – newacct