패턴을 조합하여 코드를 줄이고 가독성을 개선하자!
중복되는 코드를 줄이고 가독성을 개선하자
서버를 개발하면서 인트라넷 관련 정보를 호출하거나 데이터를 요청하고 처리하는 과정에서 비슷한코드들이 반복되는 경우가 많았습니다. 이러한 문제를 조금 해결해보기 위해 다양한 패턴을 적용해보았습니다.
strategy 패턴을 이용하여 큰 틀을 만들자
public interface ParserDocument { String getURL() ; default Document getDocument() throws IOException{ Connection connection = Jsoup.connect(getURL()) .timeout(1000 * 60) .header("Accept", "*/*") .header("Content-Type", "text/html; charset=UTF-8") .header("Accept-Encoding", "gzip, deflate, br") .header("Connection", "Keep-Alive") .header("X-Powered-By", "Team Space") .header("User-Agent", "Team-Space/BibleAlarm") .method(Connection.Method.GET); return connection.get(); } Elements parserDocument(); }
시작전 인터페이스를 하나 정의했습니다. parserDocument(), getDocument(), getURL() 를 정의하고 메소드별 흐름을 처리할 수 있도록 정의했습니다.
여기서 getDocument() 은 다른 메소드들과 다르게 default를 정의를 했습니다. 이것을 클래스로 만들어 상속을 안한 이유는 클래스의 의존성이 강한 결합 문제와 다중 상속이 되지 않기 때문에 나중에 문제가 될 것이라 생각했습니다. (나중에는 클래스 관리문제도 크게 발생할 것으로 생각했습니다)
... abstract class BaseCategory implements ParserDocument { @Value("${LIBRARY.BIBLE.URL}") private String URL; protected abstract String getQuery(); @Override public Elements parserDocument() { try { return getDocument() .getElementsByClass("col-md-9 sponge-main-book book") .select(getQuery()); } catch (NullPointerException e) { log.error("Category NullPointerException"); throw new SpaceRuntimeException(NoticeErrorCode.NOT_FOUND_PAGE); } catch (IOException e) { log.error("Category IOException"); throw new NoticeIOException(NoticeErrorCode.NOT_FOUND_PAGE); } catch (Exception e) { log.error("Category Exception{}", e.getMessage()); throw e; } } ...
... public class BestBook extends BaseCategory implements ParserDocument { @Override protected String getQuery() { return "#book-best > div:nth-child(2) > div > ul > li > a"; } } ...
부모 클래스는 Domain에서 처리되는 중복이 되는 코드들을 Override로 정의하고, 상황에 따라서 abstract 메소드를 만들어 자식 클래스에서 정의하도록 만들었습니다.
자식 클래스는 부모클래스에서 abstract 메소드만 정의하여 클래스를 만들어줍니다. 인터페이스와 클래스 상속을 조합하여 중복될 수 있는 코드들은 줄이고 캡슐화를 하였습니다.
또한 큰 장점은 자식 클래스에서 기능이 조금 달라져야 한다면 재정의만 하면 크게 변경사항없이 처리할 수 있다는 점입니다.
Factory 패턴을 이용하여 주입히자
... class BookCategoryFactoryImpl implements BookCategoryFactory{ private final ApplicationContext context; public BookCategoryFactoryImpl(ApplicationContext context) { this.context = context; } @Override public ParserDocument getCategory(CategoryType type) { switch (type) { case BEST_BOOK -> { return context.getBean(BestBook.class); } case NEW_BOOK -> { return context.getBean(NewBook.class); } case EBOOK_BOOK -> { return context.getBean(EBook.class); } case RENTAL_BOOK -> { return context.getBean(RentalBook.class); } case BOOK_NOTICE -> { return context.getBean(BookNotice.class); } default -> throw new SpaceRuntimeException(NoticeErrorCode.TYPE_ERROR); } } } ...
이제 필요한 기능들을 정의하고 *enum* 값에 따라서 클래스를 반환시켜 주입을 할 수 있도록 도와줍니다.
... @Override public List<BookCategory> parserBookCategory(CategoryType type) { return categoryFactory.getCategory(type) .parserDocument() .stream() .map(homeUtil::toCategory) .collect(Collectors.toList()); } ...
그러면 enum값에 따라서 주입을 하여 데이터를 처리하고 반환할 수 있게 함으로 하나의 Facade 패턴도 만들어지게됩니다. 이와 같이 중복된 코드를 생략하고, strategy 패턴이 이용되어 다른 클래스 수정없이 확장하거나 기능을 늘릴 수 있어 유지관리 측면을 개선할 수 있었습니다.
댓글
이 글 공유하기
다른 글
-
Python에서 Java로 마이그레이션하게 된 이유
Python에서 Java로 마이그레이션하게 된 이유
2024.06.23 -
잘못된 에러 핸들링과 로그에 관하여
잘못된 에러 핸들링과 로그에 관하여
2024.04.16로그레벨에 관하여 개발을 진행하다보면 로그를 테스트나 서비스 상태나 장애 파악을 위해 많이 쓰게 됩니다. 그래서 단계에 따른 레벨을 사용하게 됩니다. log4j 기준으로 RACE, DEBUG,INFO, WARN, ERROR, FATAL 으로 구분을 지어 사용합니다. ⭐ 로그레벨 정의 TRACE : 추적 레벨은 DEBUG보다 좀 더 상세한 정보를 나타낸다. DEBUG : 프로그램을 디버깅하기 위한 정보를 지정한다 INFO : 상태변경과 같은 정보성 메세지를 나타낸다. WARN : 처리 가능한 문제, 향후 시스템 에러의 원인이 될 수 있는 경고성 메세지를 나타낸다. ERROR : 요청을 처리하는 중 문제가 발생한 경우이다. FATAL : 아주 심각한 에러가 발생한 상태로 시스템적으로 심각한 문제가 발생해 어…
댓글을 사용할 수 없습니다.