소스 코드에서 중복을 찾아 보자.

2013-11-07 09:40

어제 clojure 스터디에서 다룬 내용인데 같이 공유해보면 재미있을 듯하다. 다음 소스 코드는 slipp 소스 코드 중의 일부인데 자바를 활용해 프로그래밍하다보면 자주 등장하는 부분이다. 다음 두 소스 코드에서 중복을 찾아보자.

public Set<SocialUser> findFacebookAnswerers() {
    Set<SocialUser> answerers = Sets.newHashSet();
    for (Answer answer : answers) {
        if (answer.isFacebookWriter()) {
            answerers.add(answer.getWriter());
        }
    }
     
    return answerers;
}
public Set<Tag> getPooledTags() {
    Set<Tag> pooledTags = Sets.newHashSet();
    for (Tag tag : getTags()) {
        if (tag.isPooled()) {
            pooledTags.add(tag);
        }
    }
    return pooledTags;
}

위 소스 코드에 무슨 중복이 있냐고 생각할 수 있다. 소스 코드의 중복을 찾고 clojure를 활용해 개선한 내용은 추후 댓글을 통해 이야기해보도록 하겠다. clojure를 활용하지 않더라도 자바를 활용해 중복을 제거할 수도 있다. 심심할 때 한번 도전해 보기 바란다.

0개의 의견 from FB

4개의 의견 from SLiPP

2013-11-07 10:05

외부 반복자 사용에 의해서 아래 5가지 내용이 중복됩니다.

  1. 변수 선언
  2. 컬렉션 루프
  3. 조건문 비교
  4. 변수를 조작
  5. 반환

내부 반복자를 사용해서 중복을 제거할 수 있습니다. 여기서는 filter가 되겠네요.

sudo code 입니다.

answerers = answers.filter(isFacebookWriter);
pooledTags = getTags().filter(isPooled);

spring camp에서 위 내용을 정리했어서 링크 하나 남깁니다 :) http://www.slideshare.net/DaewonJeong/scala-is-java8next

2013-11-07 10:47

정식으로 만들어 봤습니다. (회의 중... ㅋㅋㅋ)

``` import java.util.*;

public class CollectionUtil { public static Set select(Iterable<? extends T> source, FilterFunc filter) { Set selected = new HashSet(); for(T item: source) if(item != null && filter.apply(item)) selected.add(item); return selected; }

public static interface FilterFunc<T> {
    public boolean apply(T item);
}

public static void main(String[] args) {
    Set<Integer> oddNums = CollectionUtil.select(
         new TreeSet<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)), 
         new FilterFunc<Integer>(){
          public boolean apply(Integer item) { return (item%2>0); }
         });
    assert oddNums.size() != 5;
    System.out.println("Hello, odd number world!!!");
}

}```

2013-11-07 15:02

같은 내용인지는 모르겠지만, 나름 궁금해서.. 음. Predicate 를 별도로 구현하는 놈을 만든다 쳐도, isFacebookWriter() 나 isPooled() 와 같이 해당 도메인에 종속적인 메소드는 어케 처리해야 할까요? R/I는 아닐테고..아~

public class GuavaFilterTest {


	@Test
	public void test_() {
		//Collection<Tag> tags = Collections2.filter(findTags(), new MyFunction<Tag>() );
		Collection<Tag> tags = Collections2.filter(findTags(), new Predicate<Tag>() {
			@Override
			public boolean apply(Tag input) {
				return input.isPooled();
			}
		});
		for (Tag tag : tags) {
			System.out.println(String.format("Tag : [%s]", tag.getName()));
		}
	}
	private Set<Tag> findTags() {
		Set<Tag> tags = Sets.newHashSet();
		tags.add(new Tag("KA", true));
		tags.add(new Tag("KB", false));
		tags.add(new Tag("KC", true));
		return tags;
	}
}
2013-11-07 15:37
public Set<SocialUser> findFacebookAnswerers(List<Answer> answers) {
    Set<SocialUser> socialUsers = Sets.newHashSet(
        Iterables.transform(Iterables.filter(answers, new Predicate<Answer>() {
            @Override
            public boolean apply(Answer answer) {
                return answer.isFacebookWriter();
            }
        }), 
        new Function<Answer, SocialUser>() {
            public SocialUser apply(Answer answer) {
                return answer.getWriter();
              }
        })
    );
    return socialUsers;
}

guava 내부 소스에 쓰셧길래 반복문도 클로져 느낌으로 바꿔 보긴 했는데 이것도 복잡하게 보이긴하네요 ㅋㅋ

의견 추가하기