Skip to content

dongsik2026/refactoring-cases

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Refactoring Cases

이 예제는 extract till you drop(extract method를 수행할 수 없을 때까지 수행)을 한 후에 남게되는 많은 작은 private method들을 역할에 맞게 다른 클래스로 위치시키는 것을 보여준다.

extract till you drop은 github, youtube에서 자세히 보실 수 있습니다.

1. 최초 클래스

package abstract_till_you_drop;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

abstract class SymbolReplacer {
    protected String stringToReplace;
    protected List alreadyReplaced = new ArrayList();

    SymbolReplacer(String s) {
        this.stringToReplace = s;
    }

    String replace() {
        Pattern symbolPattern = Pattern.compile("\\$([a-zA-Z]\\w*)");
        Matcher symbolMatcher = symbolPattern.matcher(stringToReplace);
        while (symbolMatcher.find()) {
            String symbolName = symbolMatcher.group(1);
            if (getSymbol(symbolName) != null && !alreadyReplaced.contains(symbolName)) {
                alreadyReplaced.add(symbolName);
                stringToReplace = stringToReplace.replace("$" + symbolName, getSymbol(symbolName));
            }
        }
        return stringToReplace;
    }

    abstract protected String getSymbol(String symbolName);
}

2. 테스트 추가

abstract method에 대한 구현체를 추가.

package abstract_till_you_drop;

public class MyReplacer extends SymbolReplacer {
    MyReplacer(String s) {
        super(s);
    }

    @Override
    protected String getSymbol(String symbolName) {
        return "__";
    }
}

characterization test를 추가한다.

package abstract_till_you_drop;

import org.junit.Test;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

public class SymbolReplacerTest {
    @Test
    public void foo() {
        MyReplacer replacer = new MyReplacer("$ss aa $bb dd ff ss");
        assertThat(replacer.replace(), is("xx"));
    }
}

make it pass

테스트를 실행시켜서 시스템이 원하는 값을 알아내고 이를 이용하여 테스트를 성공시킨다. <- characterization test

3. Prepare Extract Methods

symbolPattern, symbolMatcher를 field로 추출 큰 메소드를 작은 메소드를 extract하기 전의 사전 작업. 이 작업을 수행하면 extract method할 때 parameter로 전달할 필요가 없어진다.

4. Extract method: replaceAllInstances

5. Extract method: shouldReplaceSymbol

6. Extract method: replaceSymbol

7. Change while to for

8. Extract method: nextSymbol

9. Change inheritance to composition

prepare

SymbolTranslator 클래스를 생성

make it pass

10. Extract class - SymbolIterator

  • symbolMatcher, symbolPattern는 nextSymbol에서만 사용됨.
  • 다른 속성들보다 보다 응집도가 높거나 밀접하게 관계된 2개 이상의 속성들이 존재하는 경우가 있다.
  • 이런 속성들을 별도의 클래스로 추출하면 가독성이 좋아진다.

prepare

symbolMatcher, symbolPattern를 SymbolIterator로 이동시키기 위해 static으로 변경. 그래야 intellij에서 move 가능.

move members

move nextSymbol to SymbolIterator

make it work

11. Extract method - symbolExpression

가독성을 위해 아래와 같이 extract method를 수행

12. Move symbolExpression to SymbolTranslator

symbolExpression은 SymbolTranslator와 밀접한 관계를 갖는다. 따라서 SymbolTranslator로 이동시킨다.

13. Feature envy

replaceSymbol은 symbolTranslator의 2개의 메소드를 호출한다. feature envy다. SymbolTranslator의 translate 메소드로 이동하자.

prepare: extract method translate

2개의 메소드 호출을 IDE의 기능으로 이동시킬 수 없다. 먼저 2개의 메소드 호출을 translate 함수로 추출한다.

move method translate to SymbolTranslator

refactoring

symbolExpression는 더 이상 외부에서 호출되지 않으니 private으로 변경

About

refactoring cases

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages