객체생성패턴

minus·2022년 12월 22일
0

생성자 패턴

생성자를 선언하고 그 생성자로 객체를 초기화

=> 비지니스 로직 수정, DB 스키마 변경 등으로 인해 클래스 구조가 변경되면 생성자를 추가, 변경해야할 필요가 있음

정적 메소드 패턴(Static Factory)

생성자가 아닌 static 메소드를 이용해 객체를 생성

LocalDateTime.now(); // 현재 시간을 담은 LocalDateTime 객체 생성

수정자 패턴(getter/setter)

특정 필드에 접근할 수 있는 메소드를 선언해 간접적으로 값을 변경하는 패턴

  • 클래스의 모든 필드에 getter/setter를 무지성 선언하는 것은 좋지않음
    => setter를 선언하지 않음으로서 해당 필드 데이터 변경 가능성을 차단할 수 있고, 해당 필드가 변경되지 않는 필드임을 알려줄 수도 있음
    또한 불필요한 데이터 변경 여지가 있어 이후 유지보수 시 데이터 변경 시점을 파악하기 어려울 수 있음

빌더 패턴

생성자를 사용한 초기화와 달리 파라미터에 의존적이지 않은 유연한 객체 초기화 가능

class Class {
	String A,B,C;
}

Class obj = Class.builder().A("a").B("bb").build();

modifiable / unmodifiable collection

참조변수, 객체가 가진 필드의 변경은 예상치 못한 side effect를 유발할 수있음

1) setter 사용을 줄이기
2) unmodifable collection (ex: Collections.unmodifiableList(list))
3) 데이터를 전달받는 객체(DTO)와 비지니스 로직을 처리하고 data layer에 접근하는데 사용하는 객체(VO,Entity)로 계층을 분리 (ex: JPA 활용)

와 같은 방법으로 객체가 변경될 수 있는 가능성을 낮출 수 있음

자바에서 Stream API를 사용할 경우 기존 Collection 객체를 변경하지 않고 중간연산 결과를 확인하거나, Stream에 고차함수를 거친 새로운 결과를 생성할 수 있음(side effect 제거)

DTO, VO, Entity

DTO(Data Transfer Object)는 view layer에서 데이터를 전달받고 전달하는데 사용하는 객체로 정의할 수 있음
view layer에서 사용하기 때문에 비지니스 로직을 포함하거나 영향을 받아 변경되지 않아야함

VO(Value Obejct), Entity는 data layer와 데이터를 주고받고 비지니스 로직에서 사용할 수 있는 객체로 정의할 수 있음
비지니스 로직에 의해 데이터가 변경될 가능성이 있으므로 주로 getter/setter를 통해 데이터를 가져오고 변경하는 경우가 많음
=> 데이터를 직접 변경하는 경우 로직이 복잡해지거나 비동기 처리를 하는 등 흐름을 알기 어려운 경우 객체 변화를 쉽게 파악하기 어려울 수 있음

setter를 선언하지 않거나 직접 호출해 사용하지 않으면 어떨까?

setter가 없다고 가정하면 Entity는 선언할 때 초기화 해준 필드 값을 그대로 가지고 있다고 생각할 수 있고 그에 따른 side effect도 피할 수 있음(Builder 패턴으로 Entity,VO 객체 선언!!)
setter가 없으면 아예 필드 값을 변경할 수 없느냐하면 그것은 아님

getter/setter 선언없이 데이터 접근/변경하기

대표적인 비지니스 로직 형태를 생각해보면

- obj.getAge()를 통해 얻은 나이를 특정 값과 비교해 특정 로직 수행
- 20xx.12.31이 지나면 obj.Age 값을 obj.setAge(obj.getAge()+1)으로 변경

위와 같이 obj의 age에 대해 getter/setter를 사용하는 예를 들 수 있음

두 예제를 getter/setter 없이 구현하기 위해 클래스에 새로운 메소드를 선언할 수 있음

class class {
	Integer age;
    
    public Boolean isNewYear(){
    	// 새로운 해가 되었으면 return true
    }
    
    public changeAgeWhenNewYear() {
    	Integer currentAge = age;
        
        System.out.println("current age = %d", currentAge);
        
    	if(isNewYear()){
        	age += 1
            System.out.println("Happy New Year");
        }
    }

}

위와 같이 클래스 내부적으로 필드에 접근해 데이터에 접근/변경하도록 변경하면 메소드의 역할을 명확하게 기술할 수 있고, 직접적인 데이터 변경으로 인한 side effect도 최소화할 수 있음

profile
안녕하세요

0개의 댓글