상세 컨텐츠

본문 제목

제어 플래그 삭제

자바강좌/리팩토링

by somiyuralove 2020. 1. 8. 00:24

본문

dbfile.txt
0.00MB
Main.java
0.00MB
SimpleDatabase.java
0.00MB

플래그(flag)란 원래 "깃발"이라는 뜻.

 

프로그래밍에서는 "상태를 기록하고 처리 흐름을 제어하기 위한 boolean 타입 변수"를 의미합니다. 

 

쉽게 말에서 참과 거짓을 나타내주는 플래그입니다.

 

특히 처리 흐름을 제어할때 사용하는 플래그로 제어 플래그(control flag)라고 합니다.

 

제어 플래그가 꼭 나쁜것은 아니지만, 무분별하게 사용하면 처리 흐름을 파악하기 어려워져 때로는 프로그램 전체를 파악하는데 어려움을 겪기도 합니다.

 

그럼 제어 플래그 삭제(Remove Control Flag) 리펙토링에 대해서 알아보겠습니다.

 

이 방법은 제어 플래그를 삭제해서 프로그램을 읽기 편하게 만드는데, 제어 플래그 대신에 break, continue, return 등을 써서 처리 흐름을 제어합니다.

 

* 예제 프로그램(1)

 

1. FindInt.java

package examJava;

public class FindInt {
public static boolean find(int[] data, int target) {
boolean flag = false;
for (int i=0; i<data.length && !flag; i++) {
 if(data[i] == target) {
  flag = true;
 }
}
  return flag;
 }
}

 

위의 코드는 flag라는 제어 플래그를 사용합니다. for 반복은 i가 data.length보다 작고 flag가 false일때 동작합니다.

만약 target을 찾았다면 제어 플래그 flag는 true가 반환됩니다. 그리고 반환값으로 flag를 반환합니다.

이 코드는 나쁜 코드입니다.

 

2. Main.java

package examJava;

public class Main {
public static void main(String[] args) {
int[] data = {
1, 9, 0, 2, 8, 5, 6, 3, 4, 7,
};
if(FindInt.find(data, 5)) {
 System.out.println("Fonud!");
} else {
 System.out.println("Not found...");
}
}
}

 

위의 Main.java는 배열 data안에 5가 들어있는지 조사합니다.

 

위의 코드를 리팩토링해보도록 하겠습니다.

 

* break를 사용한 리팩토링 실행

일단 flag라는 변수명은 의미가 모호 하므로 found라는 변수명으로 변경합니다.

 

public class FindInt { 
public static boolean find(int[] data, int target) { 
boolean found = false; 
for (int i=0; i<data.length; i++) { 
 if(data[i] == target) { 
  found = true; 

  break;
 } 
} 
  return found; 
 } 
}

 

* return을 사용한 리팩토링 실행

 

break로 리팩토링을 마친 코드를 다시 리팩토링할 수 있습니다.

이 코드는 found에 true를 할당 한 시점에 반복문을 종료하는게 아니라 메서드 전체를 종료해도 문제가 없습니다.

그러므로 break부분을 return을 써서 다시 변경해 봅니다.

반환값으로 true를 직접 지정합니다.

 

package examJava;

public class FindInt {
public static boolean find(int[] data, int target) {
for (int i=0; i<data.length; i++) {
if(data[i] == target) {
return true;
}
}

return false;
}
}

 

* 예제 프로그램(2)

1. SimpleDatabase.java

 

package simpleDatabase;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class SimpleDatabase {
private Map<String, String> _map = new HashMap<String, String>();
public SimpleDatabase(Reader r1) throws IOException {
BufferedReader r2 = new BufferedReader(r1);
boolean flag = false;
String tmp;
while (!flag) {
tmp = r2.readLine();
if(tmp == null) {
flag = true;
} else {
boolean flag2 = true;
StringBuffer s1 = new StringBuffer();
StringBuffer s2 = new StringBuffer();
for (int i=0; i<tmp.length(); i++) {
char tmp2 = tmp.charAt(i);
if(flag2) {
if(tmp2 == '=') {
flag2 = false;
} else {
s1.append(tmp2);
}
} else {
s2.append(tmp2);
}
}
String ss1 = s1.toString();
String ss2 = s2.toString();
_map.put(ss1, ss2);
}
}
}

public void putValue(String key, String value) {
_map.put(key, value);
}

public String getValue(String key) {
return _map.get(key);
}

public Iterator iterator() {
return _map.keySet().iterator();
}
}

 

2. Main.java

package simpleDatabase;

import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;

public class Main {
public static void main(String[] args) {
try {
SimpleDatabase db = new SimpleDatabase(new FileReader("C:/dev/workspace/examJava/src/simpleDatabase/dbfile.txt"));
Iterator it = db.iterator();
while(it.hasNext()) {
String key = it.next();
System.out.println("KEY: \"" + key + "\"");
System.out.println("VALUE: \"" + db.getValue(key) + "\"");
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

 

3. dbfile.txt

 

hyuki@example.com=Hiroshi Yuki
sato@example.com=Sato Hanako
tomura@example.com=Tomura

 

위의 리팩토링 하기전 코드에서 SimpleDatabase.java의 코드는 알기 어려운 변수로 인해서 소스를 이해하기가 어렵습니다. 일단 알아보기 쉽지 않은 변수를 아래와 같이 변경합니다.

 

public SimpleDatabase(Reader r) throws IOException {
BufferedReader reader = new BufferedReader(r);
boolean reading = false;
String line;
while (!reading) {
line = reader.readLine();
if(line == null) {
reading = true;
} else {
boolean scanningKey = true;
StringBuffer keyBuffer = new StringBuffer();
StringBuffer valueBuffer = new StringBuffer();
for (int i=0; i<line.length(); i++) {
char c = line.charAt(i);
if(scanningKey) {
if(c == '=') {
scanningKey = false;
} else {
keyBuffer.append(c);
}
} else {
valueBuffer.append(c);
}
}
String key = keyBuffer.toString();
String value = valueBuffer.toString();
_map.put(key, value);
}
}
}

 

위의 코드를 scanningKey로 문자열을 조사하던 부분을 indexOf 함수로 호출하고 외부 반복 제어 플래그인 flag는 break로 삭제합니다.

 

package simpleDatabase;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class SimpleDatabase {
private Map<String, String> _map = new HashMap<String, String>();
public SimpleDatabase(Reader r) throws IOException {
BufferedReader reader = new BufferedReader(r);
while (true) {
String line = reader.readLine();
if(line == null) {
break;


int equalIndex = line.indexOf("=");
if(equalIndex > 0) {
String key = line.substring(0, equalIndex);
String value = line.substring(equalIndex + 1, line.length());
_map.put(key, value);
}
}
}

public void putValue(String key, String value) {
_map.put(key, value);
}

public String getValue(String key) {
return _map.get(key);
}

public Iterator iterator() {
return _map.keySet().iterator();
}
}

 

* 정규 표현식으로 변경

package simpleDatabase;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SimpleDatabase {
private Map<String, String> _map = new HashMap<String, String>();
private static Pattern _pattern = Pattern.compile("([^=]+)=(.*)");
public SimpleDatabase(Reader r) throws IOException {
BufferedReader reader = new BufferedReader(r);
while (true) {
String line = reader.readLine();
if(line == null) {
break;


Matcher matcher = _pattern.matcher(line);
if(matcher.matches()) {
String key = matcher.group(1);
String value = matcher.group(2);
_map.put(key, value);
}
}
}

public void putValue(String key, String value) {
_map.put(key, value);
}

public String getValue(String key) {
return _map.get(key);
}

public Iterator iterator() {
return _map.keySet().iterator();
}
}

관련글 더보기

댓글 영역