-
[Java] Effective Java: 제 2장 (1) 생성자 대신 정적 팩터리 서드를 고려하라Book/Effective Java 2022. 11. 22. 22:52
이 글은 이펙티브 자바 책에 대해 정리하며 책에 있는 부분 중 모르는 내용을 긁어와서 정리하는 글입니다.
모르는 부분이 아니더라도 번역체라 이해하기 힘든 부분을 정리합니다.
1. 정적 팩터리 메서드(static factory method)
클라이언트가 클래스의 인스턴스를 얻는 전통적인 수단은 public 생성자이다.
- 여기서 클래스와 인스턴스, 그리고 객체의 개념에 대해서 살펴보자.
객체 지향 언어란 프로그램을 다수의 객체로 만들고, 이들끼리 서로 상호작용하도록 만드는 프로그래밍 언어이다.
클래스의 개념
- 객체를 만들어 내기 위한 설계도 혹은 틀
- 연관되어 있는 변수와 메서드의 집합
객체의 개념 = 클래스의 인스턴스
- 객체는 모든 인스턴스를 대표하는 포괄적인 의미를 갖는다.
- 소프트웨어 세계에 구현할 대상
인스턴스의 개념
- 구체적인 실체
ex ) '사과'는 객체, 오늘 먹은 '사과 1개'는 인스턴스
그러니까 보통 우리가 인스턴스를 얻을 때 클래스의 생성자로 얻는다는 말이다. Apple이라는 클래스의 객체를 얻으려면
Apple apple = new Apple();
이렇게 생성자로 얻는 방법이 일반적이다.
클래스는 생성자와 별도로 정적 팩터리 메서드(static factory method)를 제공할 수 있다. 정적 팩터리 메서드는 그 클래스의 인스턴스를 반환하는 정적 메서드를 의미한다.
여기서 factory라는 말이 익숙하지 않다. factory라는 말을 이해하기 위해서는 디자인 패턴을 먼저 이해해야한다.
디자인 패턴은 소프트웨어를 설계할 때 특정 맥락에서 자주 발생하는 고질적인 문제들이 또 발생했을 때 재사용할 수 있는 훌룡한 해결책이다.
패턴이란?
- 각기 다른 소프트웨어 모듈이나 기능을 가진 다양한 응용 소프트웨어 시스템들을 개발할 때도 서로 간테 공통되는 설계 문제가 존재하며 이를 처리하는 해결책 사이에도 공통점이 있다. 이러한 유사점을 패턴이라고 한다.
- 패턴은 공통의 언어를 만들어주며 팀원 사이의 의사 소통을 원활하게 해주는 아주 중요한 역할을 한다.
패턴의 구조
- 콘택스트(context)
- 문제가 발생하는 여러 상황을 기술한다. 즉, 패턴이 적용될 수 있는 상황을 나타낸다. 경우에 따라는 패턴이 유용하지 못한 상황을 나타내기도 한다.
- 문제(problem)
-패턴이 적용되어 해결될 필요가 있는 여러 디자인 이슈들을 기술한다. 이 때 여러 제약사항과 영향력도 문제 해결을 위해 고려해야 한다.
- 해결(solution)
- 문제를 해결하도록 설계를 구성하는 요소들과 그 요소들 사이의 관계 , 책임 협력 관계를 기술한다.
정적 팩터리 메서드 살펴보기!
팩토리라는 단어는 디자인 패턴의 종류인 GoF 디자인 패턴 중 팩토리 패턴에서 유래된 단어이고, 객체를 생성하는 역할을 분리하겠다는 취지가 담겨있다.
팩토리 메소드 패턴은 객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지 서브 클래스에서 결정하게 만드는 패턴이다.
팩토리 패턴의 목적성
객체 지향 디자인 패턴의 기본 원칙은 코드를 수정하지 않아도 모듈의 기능을 확장하거나 변경할 수 있어야 한다는 의미다. 그래서 수정이 일어날 가능성이 큰 부분과, 그렇지 않은 부분을 분리하는 것이 좋다. 객체는 속성과 함수가 변경 또는 추가될 수 있다. 이에 따라 객체의 생성을 담당하는 코드는 변경의 가능성이 높다.
결과적으로 객체의 생성을 담당하는 클래스를 한 곳에서 관리하여 결합도를 줄이기 위하여 팩토리 패턴이 나타나게 되었다.
정적 팩토리 메서드란 객체 생성의 역할을 하는 클래스 메서드이다.
책에서는 클래스의 인스턴스를 반환하는 단순한 정적메서드라고 얘기한다.
public static Boolean valueOf(boolean b){ return b? Boolean.TRUE : Boolean.FALSE; }
이 코드는 boolean 기본 타입의 박싱 클래스인 Boolean에서 발췌한 간단한 예이다. 이 메서드는 기본 타입인 boolean 값을 받아 Boolean 객체 참조로 변환해 준다.
클래스는 클라이언트에 public 생성자 대신 정적 팩터리 메서드를 제공할 수 있다.
이 방식은 장점과 단점을 가진다.
장점 다섯가지
1. 이름을 가질 수 있다.
생성자에 넘기는 매개변수와 생성자 자체만으로 반환될 객체의 특성을 제대로 설명하지 못한다. 반면 정적 팩터리 메서드를 사용하면 반환할 객체의 특성을 제대로 설명하지 못한다.
생성자인 BigInteger(int, int, Random)과 정적 팩터리 메서드인 BigInteger.probalePrime 중 어느 쪽이 '값이 소수인 BigInteger를 반환한다'는 의미를 잘 설명할 것 같은지 생각해 보라.
하나의 시그니처로는 생성자를 하나만 만들 수 있다.
2. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.
3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.
4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
5. 정적 패터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
단점 두가지
1. 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.
2. 정적 팩터리 메서드는 프로그래머가 찾기 어렵다.