2017-09-06 TIL

더 즐겁고 행복하게 일할려면..

  • 자기가 하고 싶은것만 하자
    • 하지만 현실에선 힘들다.
  • 일(노동) 자체에 부정적인 시각이 있다.
    • 일을 자아실현의 도구로 생각하자.

자동차 경주 게임 구현

인터페이스, 익명클래스, 람다 연습

  • 모든 수의 합을 구하는 메서드
    public int sumAll(List<Integer> numbers) {
    int total = 0;
    for (int number : numbers) {
      total += number;
    }
    return total;
    }
    
  • 짝수의 합을 구하는 메서드
    public int sumAllEven(List<Integer> numbers) {
    int total = 0;
    for (int number : numbers) {
        if (number % 2 == 0) {
            total += number;
        }
    }
    return total;
    }
    
  • 위의 두 메서드가 구현되어 있는 상황에서 List에 담긴 값중 3보다 큰 수만을 더해야 하는 메서드를 구현해야한다.
    public int sumOverThree(List<Integer> numbers) {
      int total = 0;
      for (int number : numbers) {
          if (number > 2) {
              total += number;
          }
      }
      return total;
    }
    
  • 위 3개의 메서드에서 많은 중복이 발생한다. 중복을 제거해 보자.
  • 변경되는 부분과 변경되지 않는 부분의 코드를 분리한다.
  • 변경되지 않는 부분
    int total = 0;
    for (int number : numbers) {
          // if문을 제외한 부분은 변경이 일어나지 않는다.
          total += number;
    }
    return total;
    
  • 변경되는 부분
    for (...) {
      if (number > 2) { -> if의 조건문에서 변경이 일어난다.
          ...
      }
    }
    
  • 변경되는 부분을 인터페이스로 추출해보자.
    public interface AddStrategy {
      boolean addNumber(int number);
    }
    
  • 인터페이스로 공통된 부분을 추출하면 인터페이스의 구현클래스를 생성해야한다.
  • 기본 합의 조건을 구하는 구현클래스
    public class DefaultSum implements AddStrategy {
    @Override
    boolean addNumber(int number) {
        return true;
    }
    }
    
  • 짝수의 합의 조건을 구하는 구현 클래스
    public class EvenSum implements AddStrategy {
    @Override
    boolean addNumber(int number) {
        return (number%2 == 0);
    }
    }
    
  • 3보다 큰 수의 조건을 구하는 구현 클래스
    public class OverThreeSum implements AddStrategy {
    @Override
    boolean addNumber(int number) {
        return (number > 3);
    }
    }
    
  • 구현된 클래스를 인터페이스를 이용해 적용해 보자.
    public int sum(List<Integer> numbers, AddStrategy addStrategy) {
      int total = 0;
      for (int number : numbers) {
        if (addStrategy.addNumber(number)) {
          total += number;
        }
      }
      return total;
    }
    
    
    public int sumAll(List<Integer> numbers) {
      return sum(numbers, new DefaultSum());
    }
    
    public int sumAllEven(List<Integer> numbers) {
      return sum(numbers, new EvenSum());
    }
    public int sumOverThree(List<Integer> numbers) {
      return sum(numbers, new OverThreeSum());
    }
    
    
  • 인터페이스를 이용해서 중복을 뽑아 낸다고 코드 수가 줄어드는 것이 아니다.

  • 단지 공통기능부분에서 조금 다른 부분의 코드를 공통되게 적용할 수 있게 하는것이다.

  • 하지만 인터페이스를 이용한 구현클래스의 수가 늘어날수록 클래수의 수가 기하급수적으로 많아진다.
  • 이를 해결하기 위해서 익명클래스를 이용하여 인터페이스를 구현할 수 있다.
  • 익명클래스를 이용해 구현클래스를 이용하지않고 인터페이스를 구현할 수 있다.

    public int sum(List<Integer> numbers, AddStrategy addStrategy) {
      int total = 0;
      for (int number : numbers) {
        if (addStrategy.addNumber(number)) {
          total += number;
        }
      }
      return total;
    }
    
    
    public int sumAll(List<Integer> numbers) {
      return sum(numbers, new AddStrategy() {
    
        @Override
        public boolean addNumber(int number) {
          return true;
        }
      });
    }
    
    public int sumAllEven(List<Integer> numbers) {
      return sum(numbers, new AddStrategy() {
    
        @Override
        public boolean addNumber(int number) {
          return number %2 == 0;
        }
      });
    }
    public int sumOverThree(List<Integer> numbers) {
      return sum(numbers, new AddStrategy() {
    
        @Override
        public boolean addNumber(int number) {
          return number > 3;
        }
      });
    }
    
    
  • 익명클래스를 이용해 인터페이스를 구현하면 코드가 매우 지저분해지는 것을 볼 수 있다.
  • 이를 해결하기위해 자바8에서는 람다식이 존재한다.
  • 람다식을 사용하기위해서는 인터페이스에 메서드가 단 하나만 존재해야 사용가능하다.
  • 예시

    package study;
    
    public interface AddStrategy {
    	boolean addNumber(int number);
    	// boolean Number(int number); -> 주석을   프로덕션 코드에서 에러가 발생한다.
    
    }
    
    
  • 람다식을 이용한 인터페이스의 구현

    public int sum(List<Integer> numbers, AddStrategy addStrategy) {
      int total = 0;
      for (int number : numbers) {
        if (addStrategy.addNumber(number)) {
          total += number;
        }
      }
      return total;
    }
    
    public int sumAllLamda(List<Integer> numbers) {
    return sum(numbers, (a) -> true);
    }
    
    public int sumAllEvenLamda(List<Integer> numbers) {
    return sum(numbers, (a) -> a % 2 == 0);
    }
    
    public int sumOverThreeLamda(List<Integer> numbers) {
    return sum(numbers, (a) -> a > 3);
    }
    
  • 람다식을 이용하면 인터페이스의 구현부가 엄청나게 간단해 진 것을 볼 수 있다.
  • 람다식의 사용법을 이렇다.

      // 인터페이스를 매개인자로 받는 변하지않는 공통 부분
      public int sum(List<Integer> numbers, AddStrategy addStrategy) {
        int total = 0;
        for (int number : numbers) {
          if (addStrategy.addNumber(number)) {
            total += number;
          }
        }
        return total;
      }
    
      ...
    
      // 인터페이스를 적용할 메서드
      public int sumOverThreeLamda(List<Integer> numbers) {
      return sum(numbers, (a) -> a > 3); //인터페이스의 매개인자 부분에 (매개인자) -> (조건문) 을 입력한다.
      }
    
  • 여기서 (매개인자) ->(화살표) (결과값) 의 형식을 지켜야한다.
  • 결과값을 매개인자의 리턴값을 표시해야한다. boolean이면 참/거짓을 String이면 문자열을 입력해야한다. 리턴값과 다른 타입을 입력하면 컴파일 오류가 발생한다.

  • 인터페이스, 익명클래스, 람다와 스트림의 자바8의 꽃이라 할 수 있는 부분이다. 반드시 익혀두자

Comments