crazygun22
549
2019-04-09 12:49:46 작성 2019-04-10 16:32:31 수정됨
4
1051

가독성 높은 코드 만들기 방법 #2 – 필수 멤버 변수는 생성자에서 넣어라!


생성자 함수는 객체 생성시 최초 한번 호출 됩니다.

필수 멤버 변수는 그 생성자에서 그 값을 넣어야 합니다.

아래는 생성자 함수를 만들지 않은 경우 입니다.


class Line {
 
    Point start;
    Point end;
    Color color;
 
    public void setStart(Point point){
         
        start = point;
    }
 
    public void setEnd(Point point){
 
        end = point;
    }
 
    public void setColor(Color rgb){
 
        color = rgb;        
    }
     
    public void draw() {
 
        if(color == null)
            return;
 
        if(start == null)
            return;
 
        if(end == null)
            return;
 
        // Implementation required
    }
}
 
 
int main() {
 
    Line line = new Line();  // 불안정한 상태
    line.setStart(new Point(10, 10));
    line.setEnd(new Point(20, 40));
    line.setColor(new Color(255,0,0)); // 이제 안정된 상태
    line.draw();
}


main 함수에서 Line 객체가 생성(40번째 줄) 되면,  필수 멤버 변수 start, end, color 는 null 또는 쓰레기 값을 가져 객체는 불안정한 상태가 됩니다. 이 상태에서 draw 를 호출하면 오동작 할 것입니다. 

다음으로 setStart, setEnd, setColor을 호출하고 나서야 비로서 객체는 사용 할 수 있는 안정된 상태가 됩니다. 

객체는 생성 되었는데, 다른 set 함수들을 호출하지 않으면 오동작 한다? 이상 하지 않나요? 


필수 멤버 변수는 객체 생성시, 생성자를 통해 할당 되도록 합니다. 

예제에서 멤버 변수 start, end은 Line 을 그리기 위한 필수 변수입니다. color 는 필수 변수 이지만 따로 지정하지 않을 경우 검은색으로 할당 되도록 하죠.

아래와 같이 리펙토링 해보겠습니다.


class Line {
 
    Point start;
    Point end;
    Color color;
     
    public Line(Point pointStart, Point pointEnd, Color clr) {
 
        start = pointStart;
        end = pointEnd;
        color = clr;
    }
 
    public Line(Point pointStart, Point pointEnd) {
 
        start = pointStart;
        end = pointEnd;
        color = new Color(0,0,0);
    }
 
    public void setStart(Point point){
         
        start = point;
    }
 
    public void setEnd(Point point){
 
        end = point;
    }
 
    public void setColor(Color rgb){
 
        color = rgb;        
    }
     
    public void draw() {
 
        /*  Unnecessary
        if(color == null)
            return;
 
        if(start == null)
            return;
 
        if(end == null)
            return;
        */
 
        // Implementation required
    }
}
 
 
int main() {
 
    Line line1 = new Line(new Point(10, 10), new Point(20, 40));
    line1.draw();
 
    Line line2 = new Line(new Point(10, 10), new Point(20, 40), new Color(0,255,0));
    line2.draw();
}


이제 Line 객체 생성시 start, end 값을 필수로 넣어야 객체 생성이 가능하게 되었네요.또한 필수 멤버 변수가 할당 되었다는 것을 보장 되므로 draw 함수에서 null 검사도 이제 필요 없게 되었네요. 

만약 “Line 객체 생성 후, start, end, color 가 변경이 가능해야 한다”는 요구사항 이 있을 경우에만 setStart, setEnd, setColor 함수가 필요합니다. 그렇지 않다면 저것 또한 필요 없죠.

/* 출처 */ https://crazygun22.com

6
1
  • 댓글 4

  • 잠만보 
    4k
    2019-04-10 11:10:15

    draw 함수에서 null 체크는 필요하지 않을런지요

    생성자 파라미터로 null 이 들어와버리면 ㅎㅎ

    0
  • crazygun22
    549
    2019-04-10 13:59:36 작성 2019-04-10 14:12:31 수정됨

    @잠만보

    좋은 질문입니다. ^^


    파라미터가 null 일 경우, 죽지 않을 뿐, 오동작 합니다. 오동작이나 죽는거나 둘다 일어나지 말아야 되는 상황은 마찬가지 입니다.  죽으면 안되니 대신 오동작 일으켜야 된다? 도 이상하죠.


    객체 생성에서 자격을 갖추지 못한 파라미터가 들어 올 수 있으므로 동작 중에 그런 상황을  Handling 해야 한다.  보다는 자격을 갖추지 못한 파라미터로는 객체 생성이 안 되게 하는게 더 좋습니다. 생성자 파라미터가  null 이 들어 올 수 있는 상황이 충분히 예상된다면 아래와 같이  생성 자체가 안되게 막아야 합니다.


    public Line createLine(Point start, Point end) {
    	
    	if(start == null || end == null)
    		return null;
    	
    	return new Line(start, end);
    }


    만약 "생성자 파라미터에 null 을 허용 할 것이며, 그러할 경우  draw 함수 호출 시 아무것도 그리지 않겠다" 라고 개발자가 일부러 의도 한 것이면 그건 오동작이 아닌 정상 동작입니다.

    그러할 경우 null check  하는 것은 맞습니다.


    1
  • 아플라
    473
    2019-04-16 10:03:49

    지난번에 이어 좋은글 감사합니다.

    궁금한점이 있는데, 클래스의 멤버변수가 많을경우에는 어떻게 처리해야할까요 ?

    그래서 생성자의 파라미터가 너무 많아 인스턴스 생성 코드가 길어지게된다면... 어떻게처리하시는지 궁금합니다.

    클래스가 너무 많은 정보를 담고있는건 아닌지 의심을 해봐야 하는걸까요?

    0
  • crazygun22
    549
    2019-04-17 11:47:16

    해당 클래스에 맴버 변수가 많다는 것은 그 클래스가 혼자 너무 많은 기능을 해서 그 럴 수 있습니다.

    또는 파라미터들 사이의 관계에서 묶어서 class로 만들어 줄 수 있는지를 확인 할 필요도 있습니다.

    0
  • 로그인을 하시면 댓글을 등록할 수 있습니다.