ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [디자인 패턴] 빌더 패턴 (Builder Design Pattern)
    Computer Science/Design Pattern 2022. 10. 9. 01:47
    728x90

    빌더 패턴 (Builder Pattern)

    • GoF 디자인 패턴 중 생성 패턴에 해당
    • 빌더 패턴은 복잡한 객체를 생성하는 클래스와 표현하는 클래스를 분리
    • 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공하는 패턴

    주로 클래스에 새로운 객체 생성 시, 객체에 값을 할당하는 방법

    1. 생성자 이용

    2. Setter 메서드 이용

     

    빌더 패턴이 필요한 경우

    • 클래스에 대한 속성 값이 optional 일때
      • 클래스 객체의 여러 속성 값 중 하나 null이 되는 경우
    • 데이터 입력하는 순서가 달라질 수 있을 때
      • 새로운 객체를 만들 때마다 객체 내부 인자를 어떻게 부여해서 생성해야 하는지 모르는 경우 발생

    * 기존 클래스 생성자를 이용한 객체 생성 시 명확하게 데이터 입력하는 순서를 알아야 하는 문제점 발생

     

    장점

    • 표현을 다양하게 변경 가능
    • 생성과 표현 코드를 분리
    • 복합 객체를 생성하는 절차를 세밀하게 나눌 수 있음

    코드 설명

    기존 직접 클래스 생성자를 이용한 객체 생성 방법

    클래스 다이어그램

     

    Task.java

    import java.util.Date;
    
    //일정 관리를 위해 새롭게 생성되는 일정(Task)클래스
    public class Task {
    	//Task 클래스의 속성
    	private final long id; //일정에 대한 unique identifier
    	private String summary = ""; //일정에 대한 요약
    	private String description = ""; //일정에 대한 상세 설명
    	private boolean done = false; //일정이 완료되었는지 완료되지 않았는지를 설명하는 변수
    	private Date dueDate; //해당 Task가 언제인지 기록하는 변수
    	
        
    	//Source - Generate Constructor Using Fields (생성자 만들기)
    	//Task class를 외부 클라이언트에서 생성시 생성자 활용
    	public Task(long id, String summary, String description, boolean done, Date dueDate) {
    		super();
    		this.id = id;
    		this.summary = summary;
    		this.description = description;
    		this.done = done;
    		this.dueDate = dueDate;
    	}
    }

     

    Client.java

    import java.util.Date;
    
    public class Client {
    
    	public static void main(String[] args) {
    		Task(long id, String summary, String description, boolean done, Date dueDate)
    
    	 	//생성자를 통한 객체 생성
    		//일정을 만들 때, 일정에 대한 고유 id와 summary, description에 대한 정보만 알고 있는 경우
    		Task t1 = new Task(1000,"TEST","TEST",false,null); //t1 객체 생성
            
    		//일정들이 생성될때마다 빈값, null이 들어오는 경우,
    		//객체 생성시 매번 어느 부분이 null인지 매번 체크해야 되는 경우 발생
    		Task t2 = new Task(1001,"","",false,null);
            
    		//객체 내부 인자를 어떻게 부여해야하는지 모르는 경우 발생 (입력의 순서가 바뀔 수 있을 때)
    		Task t3 = new Task(false, null, 1002, "","");
    	}	
    }

    문제점

    • Task 클래스의 생성자를 이용한 객체 생성 시, 해당 클래스의 속성을 순서대로 기입해야 한다.
    • 속성 값 중 null이 존재할 경우 어떤 속성이 null인지 항상 체크해야 한다.
    • 내부 인자를 어떻게 부여해야 하는지 모를 경우 오류 발생.

     

     

    싱글톤 패턴을 이용한 객체 생성

    빌더패턴 이용 클래스다이어 그램

     

    Task.java

    import java.util.Date;
    
    //일정 관리를 위해 새롭게 생성되는 일정(Task)클래스
    public class Task {
    	
    	private final long id; //일정에 대한 unique identifier
    	private String summary = ""; //일정에 대한 요약
    	private String description = ""; //일정에 대한 상세 설명
    	private boolean done = false; //일정이 완료되었는지 완료되지 않았는지를 설명하는 변수
    	private Date dueDate; //해당 Task가 언제인지 기록하는 변수
    	
    	//Source - Generate Constructor Using Fields (생성자 만들기)
    	//Task class를 외부 클라이언트에서 생성시 생성자 활용
    	public Task(long id, String summary, String description, boolean done, Date dueDate) {
    		super();
    		this.id = id;
    		this.summary = summary;
    		this.description = description;
    		this.done = done;
    		this.dueDate = dueDate;
    	}
    		
    	//각각의 속성 출력하기 위한 toString 클래스
    	@Override
    	public String toString() {
    		return "Task [id=" + id + ", summary=" + summary + ", description=" + description + ", done=" + done
    				+ ", dueDate=" + dueDate + "]";
    	}
    }

     

    TaskBuilder.java

    import java.util.Date;
    
    public class TaskBuilder { //Task의 객체를 대신 만들어줌
    	
    	//Task가 가지고 있는 변수(속성) 
    	private final long id; //일정에 대한 unique identifier
    	private String summary = ""; //일정에 대한 요약
    	private String description = ""; //일정에 대한 상세 설명
    	private boolean done = false; //일정이 완료되었는지 완료되지 않았는지를 설명하는 변수
    	private Date dueDate; //해당 Task가 언제인지 기록하는 변수
    	
    	// id값만 처음 인자로 받으면, 나머지는 setter이용해서 설정
    	//TaskBuilder의 생성자
    	public TaskBuilder(long id) {
    		this.id = id;
    	}
    	
    	//각 속성에 대한 setter정의. 생성자를 통해 정의된 인자 값 추후 수정을 위함
    	public void setSummary(String summary) {
    		this.summary = summary;
    	}
    
    	public void setDescription(String description) {
    		this.description = description;
    	}
    
    	public void setDone(boolean done) {
    		this.done = done;
    	}
    
    	public void setDueDate(Date dueDate) {
    		this.dueDate = dueDate;
    	}
    	
    	//TaskBuiler 객체 생성 후 실제 Task 객체 생성해야 함.
    	//TaskBuilder 객체가 보유한 값들을 활용하여 최종적으로 Task 객체를 만드는 메소드
    	public Task build() {
    		return new Task(id, summary, description, done, dueDate);
    	}
    	
    }
    • Task를 생성할 속성 값들을 setter 메서드를 통해 값을 받아올 수 있다.
    • 그 후 build() 메소드를 통해 실제 Task 객체를 생성한다.

    각각의 값이 변동될 수 있는 속성, optional 하게 받을 수 있는 속성에 대해 각각 setter를 만들었으므로,

    클라이언트는 속성의 순서를 고려할 필요가 없다.

     

     

     

    Client.java

    import java.util.Date;
    
    public class Client {
    
    	public static void main(String[] args) {
    
    		//빌더 객체를 통한 객체 생성
    		TaskBuilder taskBuilder1 = new TaskBuilder(999);
    		taskBuilder1.setSummary("TEST");
    		taskBuilder1.setDone(false);
    		taskBuilder1.setDescription("example");
    
    		//해당값을 알지 못하는 경우, 그냥 set하지 않으면 null로 이미 설정되어있음.
    		//클라이언트는 굳이 모르는값 명시 안해도된다.
    		
            //최종적으로 앞서 대입한 값에 대해 build()메소드 이용 Task 객체 생성
    		Task task1 = taskBuilder1.build(); 
    		System.out.println(task1);
    	}	
    }

     실제 클라이언트는 TaskBuilder의 객체를 생성하고 그 객체에 setter 메소드를 이용해서 변동되는 속성 값들을 순서와 상관없이 추가하고 최종적으로 build() 메소드를 사용하면 실제 Task의 객체가 생성된다.

     

     

    실행 결과

    싱글톤 패턴을 이용하여 Client에서 추가한 속성들을 포함하여 객체가 잘 생성된 것을 확인할 수 있다.

     

    728x90
    반응형

    댓글

Keydi's Tistory