2017-12-21 2 views
3

Circle 또는 Scene 중 하나를 사용하는 메서드가 두 개 있고 N 초마다 fill 값을 변경하여 백그라운드를 빨강 - 녹색 - 파랑으로 깜박입니다.두 개의 오버로드 된 메서드, 동일한 동작으로 인해 중복 코드가 발생합니다

두 가지 방법 : 분명히

private void makeRGB(Circle c) { 
    Timer t = new Timer(); 
    t.scheduleAtFixedRate(new TimerTask() { 
     @Override 
     public void run() { 
      if(c.getFill() == Color.RED) { 
       c.setFill(Color.GREEN); 
      } else if (c.getFill() == Color.GREEN) { 
       c.setFill(Color.BLUE); 
      } else { 
       c.setFill(Color.RED); 
      } 
     } 
    },0, RGB_CHANGE_PERIOD); 
} 

private void makeRGB(Scene s) { 
    Timer t = new Timer(); 
    t.scheduleAtFixedRate(new TimerTask() { 
     @Override 
     public void run() { 
      if(s.getFill() == Color.RED) { 
       s.setFill(Color.GREEN); 
      } else if (s.getFill() == Color.GREEN) { 
       s.setFill(Color.BLUE); 
      } else { 
       s.setFill(Color.RED); 
      } 
     } 
    },0, RGB_CHANGE_PERIOD); 
} 

이 나는 ​​모두를 포함하는 그들의 슈퍼 클래스를 호출하는 접근 방식을 사용할 수 없습니다 그러나 CircleScene 같은 상속 트리에없는 매우 유사하다 .setFill()/.getFill() 방법.

여기 코드 중복 제거는 어떻게해야합니까?

답변

10

일반적으로 함수/메서드/클래스에 일반 코드를 인수 분해하고 다양한 부분을 매개 변수화하여 중복 코드를 제거합니다. 이 경우 현재 채우기를 검색하는 방법과 새 채우기를 설정하는 방법이 다릅니다. java.util.function 패키지는 다음을 parametrizing에 해당하는 유형을 제공합니다, 그래서 당신은 할 수 있습니다 :

private void makeRGB(Circle c) { 
    makeRGB(c::getFill, c:setFill); 
} 

private void makeRGB(Scene s) { 
    makeRGB(s::getFill, s:setFill); 
} 

private void makeRGB(Supplier<Paint> currentFill, Consumer<Paint> updater) { 
    Timer t = new Timer(); 
    t.scheduleAtFixedRate(new TimerTask() { 
     @Override 
     public void run() { 
      if(currentFill.get() == Color.RED) { 
       updater.accept(Color.GREEN); 
      } else if (currentFill.get() == Color.GREEN) { 
       updater.accept(Color.BLUE); 
      } else { 
       updater.accept(Color.RED); 
      } 
     } 
    },0, RGB_CHANGE_PERIOD); 
} 

참고하지만, 당신이 백그라운드 스레드에서 UI를 변경해서는 안. 당신은 정말

private void makeRGB(Supplier<Paint> currentFill, Consumer<Paint> updater) { 
    Timer t = new Timer(); 
    t.scheduleAtFixedRate(new TimerTask() { 
     @Override 
     public void run() { 
      Platform.runLater(() -> { 
       if(currentFill.get() == Color.RED) { 
        updater.accept(Color.GREEN); 
       } else if (currentFill.get() == Color.GREEN) { 
        updater.accept(Color.BLUE); 
       } else { 
        updater.accept(Color.RED); 
       } 
      } 
     } 
    },0, RGB_CHANGE_PERIOD); 
} 

또는 (더 나은), use a Timeline은 주기적으로 일을해야한다.

의견에 언급 된대로 각 색상을 뒤에 오는 색상에 매핑하는 Map을 제공 할 수도 있습니다. 이 모든 결합하여 제공합니다 또한

private final Map<Paint, Paint> fills = new HashMap<>(); 

// ... 

    fills.put(Color.RED, Color.GREEN); 
    fills.put(Color.GREEN, Color.BLUE); 
    fills.put(Color.BLUE, Color.RED); 

// ... 

private void makeRGB(Circle c) { 
    makeRGB(c::getFill, c:setFill); 
} 

private void makeRGB(Scene s) { 
    makeRGB(s::getFill, s:setFill); 
} 

private void makeRGB(Supplier<Paint> currentFill, Consumer<Paint> updater) { 

    Timeline timeline = new Timeline(Duration.millis(RGB_CHANGE_PERIOD), 
     e-> updater.accept(fills.get(currentFill.get()))); 
    timeline.setCycleCount(Animation.INDEFINITE); 
    timeline.play(); 
} 
+2

하는'정적지도 <색, Coolor> nextColorMap'는 하나의'updater.accept와 다중 층'if' 문 (nextColorMap.get를 대체 할 수있는 (currentFill.get을 ()))); – 9000

+0

답변 주셔서 감사합니다, 이것은 내가 찾고있는 것입니다; 나는 '소비자'클래스를 더 볼 필요가있다. @ 9000 팁 주셔서 감사. –

+1

'Consumer' /'Supplier'를 전달하는 대신에 값을 설정하고 가져올 수 있기 때문에 단순히 속성을 전달할 수 있습니다. – fabian

관련 문제