본문 바로가기
자바로 배우는 리팩토링

널(null)객체 도입

by 킹차니 2021. 12. 28.

어떤 약을 격일로 먹어야 한다고 해보자. 그런데 이렇게 하루를 걸러서 약을 먹은 것은 쉽지 않다. "내가 오늘 먹었나? 어제는 안먹었나?"를 매일 떠올리면서 먹어야하고, 깜빡하기도 쉽다.  이러한 일이 없도록 '아무런 효과도 없는 가짜약'을 만들어서 케이스에 교대로 담아 매일 먹으면 편리할 것이다. 우리는 이러한 방법을 'null객체'를 도입하여 적용해본다.   -자바로 배우는 리패토링 입문-

 

널 객체 도입은 아래와 같은 상황에서 사용된다.

분기문으로 Null확인을 하는 코드가 너무 많다!

 

하여 우리는 Null객체를 만들어 Null을 Null객체로 치환하여 Null객체는 아무일도 하지 않도록 할 것이다.

 

예를 들어 아래와 같은 코드를

if(name != null ){
	name.display();
}

아래와 같이 수정할 수 있다.

name.display();

 

 

코드로 보자

 

Person과 Label 클래스가 있는데, Person에는 name과 mail이 저장된다. Label은 표시 가능한 문자열을 나타내는 클래스이다.

Person은 name은 반드시 존재하지만 mail은 null일 수 있다.

이들을 출력하거나, toString메소드를 보면 name혹은 mail이 null인지 확인한 후 로직을 처리하는 것이 보인다.

 

 

App에서 Person객체들을 생성한 후 이들에 대한 정보를 출력해보자.

 

실행결과:

luna는 mail을 입력하지 않아서 toString()에서 name정보만 반환되고, display에도 이름만 나오는 것을 볼 수 있다.

 

이제 널 객체를 도입하여 Person의 null확인 if문들을 없애보자. 다음과 같은 순서로 진행한다.

1. 먼저 현재 Person에서 null을 확인하는 객체는 Label객체이다. Null객체는 Label클래스의 하위 클래스로 만든다.

2.IsNull 메소드를 작성 : Null이 아닌 기존의 Lable클래스는 isNull메소드가 false를 반환하도록 하고, NullLabel은 true를 반환하도록 한다.

3. Null객체 클래스에 원본 객체(Label) doSomeThing 메소드(여기선 display) 를 override한 후 아무동작도 하지 않게 만든다.

 

코드로 보면 아래와 같다.

먼저 NullLabel클래스를 보자.

 

Label에는 isNull메소드만 새로 추가되었다.

 

 

생성자는 super로 Label에 "none"을 전달하여 생성하고,

override한 display메소드는 아무일도 하지 않는다.

 

 

이제 person에서는 Null검사를 하지 않아도 된다. NullLabel생성시 super("none")으로 Label에 문자열 "none"을 전달하여 생성하므로 toString에서 문제가 없고,  

display메소드에서는 name 혹은 mail이 null이라면 display를 실행하긴 하지만 아무 작업도 진행하지 않는다.

 

 

App을 실행해보면 결과는 다음과 같다.

 

 


 

 

보완할 점

 

1. 팩토리 메소드 패턴

위에서 null객체 도입이 적용된 코드 중 Person클래스를 보면 newNullLabel()을 사용하여 객체를 직접 new하여 사용하고 있다. 이보다는 팩토리 메서드 패턴을 도입하여 

아래와 같은 메소드를 작성한 후 반환된 NullLabel객체를 사용하여 직접적인 생성을 숨기는 것이 좋다.

public static Label newNull(){
	return new NullLabel();
}

 

 

2. 싱글톤 패턴

많은 Person들이 mail이 없을 수 있다. 이때마다 NullLabel객체를 생성하는 것은 시간과 메모리 낭비이다. 하여 싱글톤 패턴을 적용하여 NullLabel객체를 하나만 생성한 뒤 늘 동일한 NullLabel객체를 사용하는 것이 좋을 것이다.

 

3. 널 객체로 중첩 클래스사용

null객체를 도입을 통헤 null확인이 줄었지만 클래스가 하나 더 늘어났다. 하여 Label클래스 안에 중첩 클래스로 NullLabel을 만들어 사용한다면 물론 클래스 개수는 줄지 않지만 더 편리하게 관리할 수 있게 된다.

public class Label{
	...
    private static class NullLabel extends Label{
    	...
    }
}

 

이들을 모두 도입하면 Label은 아래와 같다.

 

'자바로 배우는 리팩토링' 카테고리의 다른 글

클래스 추출  (0) 2022.01.01
메소드 추출  (0) 2021.12.31
어서션(Assertion)  (0) 2021.12.25
MagicNumber를 치환하기  (0) 2021.12.22
리팩토링이란?  (0) 2021.12.22