[소프트웨어 공학] 대표적인 GOF패턴 (Strategy pattern, Template pattern)

김정민·2023년 11월 22일

3학년 2학기

목록 보기
2/3

자바를 잘하는 법은 뭘까? 우아한테크코스 프리코스를 진행하면서 자바를 잘하는 것은 결국엔 리팩토링에 능숙한 것 이라고 생각이 들었다. 더 나아가면 리팩토링 하기도 전에 처음부터 패키지 관리를 잘해서 유지 보수가 쉬운 코드를 만들 수 있는 것이라고 생각들었다.

그러던 중에 소프트웨어 공학 수업을 들으면서 GOF패턴에 대해서 알게 되었다.그중에 두가지 중요한 패턴, Strategy pattern, Template pattern 이 인상 깊었다. 이 두가지를 알면 자바를 마스터 할 수 있을 것 같았다.

프리코스를 진행하면서 가장 힘들었던 것이 어떤 문제를 MVC패턴으로 나누고, 테스트를 진행하면서 오류가 있는 코드를 고치는 것이었다. 고치는 과정에서 어떤 소스코드에 있는지도 잘 모르겠었고, 성능도 안좋아서 실행하는데 오래 걸렸다.

소프트웨어 공학 수업은 유지 보수가 쉬운 technic을 배우는 수업이었는데

  • Strategy pattern은 한 마디로 말하면 Super Class를 생성하는 것이다.
  • Template pattern은 한 마디로 말하면 Abstract Operation을 생성하는 것이다.

이 두가지 패턴 내용이 어려운건 아니다. 문제는 어떤 랜덤한 상황이 닥쳤을 때 수학문제 푸는 것 처럼 빠르게 적용을 해서 유지 보수가 쉬운 코드를 만드는 사고를 해야한다는 것이다.

예제

다음 코드를 template method를 이용해서 리팩토링을 하시오.

public class Application {
	public boolean open(String fileName) {
		boolean canRead = false;
		// check whether the file can be read!
		if ( fileName.toUpperCase().endsWith(".doc") ) {
			canRead = checkDocFile(fileName);
		}
		else if ( fileName.toUpperCase().endsWith(".xls") ) {
			canRead = checkXlsFile(fileName);
		}
		
		if ( canRead == false ) return false;
		
		boolean result = false;
		// read and process the file
		if ( fileName.toUpperCase().endsWith(".doc") ) {
			result = processDoc(fileName);
		}
		else if ( fileName.toUpperCase().endsWith(".xls") ) {
			result = processXls(fileName);
		}
		return result;
	}

	private boolean processXls(String fileName) {
		return false;
	}
	private boolean processDoc(String fileName) {
		// 주어진 file이 DOC 파일의 내용을 처리함
		return false;
	}
	private boolean checkXlsFile(String fileName) {
		// 주어진 file이 XLS 파일의 내용을 처리함
		return false;
	}
	private boolean checkDocFile(String fileName) {
		// 주어진 file이 DOC의 format인지 확인함
		return false;
	}
}

주어진 문제는 open()메소드를 가진 application을 template method 를 이용해 refactoring하는것

정답

package org.example;

public abstract class FileProcessor {

    public boolean open(String fileName) {
        boolean canRead = false;
        if(isValidFileFormat(fileName)){
            canRead = checkFile(fileName);
        }
        if(!canRead){
            return false;
        }
        return processFile(fileName);
    }

    public abstract boolean checkFile(String fileName);
    public abstract boolean processFile(String fileName);
    protected abstract boolean isValidFileFormat(String fileName);
}
package org.example;

public class doc extends FileProcessor{

    @Override
    public boolean checkFile(String fileName) {
        // 주어진 file이 DOC의 format인지 확인함
        return false;
    }

    @Override
    public boolean processFile(String fileName) {
        // 주어진 file이 DOC 파일의 내용을 처리함
        return false;
    }

    @Override
    protected boolean isValidFileFormat(String fileName) {
        return fileName.toUpperCase().endsWith(".doc");
    }
}
package org.example;

public class xls extends FileProcessor {
    
    @Override
    public boolean checkFile(String fileName) {
        // 주어진 file이 XLS 파일의 내용을 처리함
        return false;
    }

    @Override
    public boolean processFile(String fileName) {
        // 주어진 file이 XLS 파일의 내용을 처리함
        return false;
    }

    @Override
    protected boolean isValidFileFormat(String fileName){
        return false;
    }
}

내가 처음 쓴 답과 약간 달랐다.

나는 왜 application에서 fileName.toUpperCase().endsWith(".doc")를 통해서 fileName을 체크하지 않고 바로 check()로 canRead 변수를 초기화 했을까. 버젓이 적혀있는데 말이다.

isValidFormat함수 자체를 만들지 않고, 두 함수만 override했다.

곰곰히 생각해보니 'check'라는 함수를 override하니까, 그 안에 fileName을 체크하는 것도 들어가지 않을까? 라는 생각을 한거 같다.

근데 문제에서 구체적으로 주어진 조건이고, 그 말은 따로 그 기능을 발휘하는 것을 만들어야한다는 의도인데, 생각하지 못한 것이 아쉽다.

REFERENCE

[1] https://happy-coding-day.tistory.com/entry/Template-Pattern%ED%85%9C%ED%94%8C%EB%A6%BF-%ED%8C%A8%ED%84%B4-VS-Strategy-Pattern%EC%A0%84%EB%9E%B5-%ED%8C%A8%ED%84%B4

profile
computer science engineering

0개의 댓글