클래스의 객체를 얻는 수단 중 보편적인 방법은 public 생성자를 이용하는 것이다.
하지만 더 좋은 수단이 하나 더 있다.
static method를 이용하는 것이다. 정적 팩터리 메서드를 사용한다는 것은 그 클래스의 인스턴스를 반환하는 메서드를 사용하는 것이다. Boolean.valueOf는 boolean 값을 받아 Boolean 객체를 반환해준다.
public static Boolean valueOf(boolean c) {
return c ? Boolean.TRUE : Boolean.FALSE;
}
이 방식에는 public 생성자를 이용하는 방식보다 좋은 점 5가지가 있다.
첫번째, 이름을 가질 수 있다.
- public 생성자만으로는 반환될 객체의 특성을 제대로 설명하기 힘들다.
반면 정적 팩터리 메서드는 쉽게 묘사가 가능하다. 예컨대
BigInteger(int, int, Random) 와 BigInteger.getPrime 중 '값이 소수인 BigInteger를 반환'
의 의미를 더 잘 묘사하고 있는지 생각해보라.
두번째, 호출할때마다 새로운 인스턴스를 반환할 필요가 없다.
불변 클래스와 같이 불필요한 객체 생성을 막을 수 있고 같은 객체가 자주 요청되는 상황에
성능을 상당히 끌어올릴 수 있고 인스턴스의 생성주기 통제가 쉬워진다. 이런 클래스를
인스턴스 통제(instance-controlled) 클래스라고 한다. 인스턴스를 통제한다는 것은 클래스를
싱글톤으로 만들수도, 인스턴스화 불가로 만들수도, 불변클래스의 동치인 인스턴스가 단하나 임을
보장할 수 있게된다는 것이다.public class StaticFactoryMethod { private static final StaticFactoryMethod STATIC_FACTORY_METHOD = new StaticFactoryMethod(); private StaticFactoryMethod() {} static public StaticFactoryMethod getNewInstanceByNumber() { return STATIC_FACTORY_METHOD; } } public static void main(String args[]){ StaticFactoryMethod staticFactoryMethod = StaticFactoryMethod.getNewInstance(); StaticFactoryMethod staticFactoryMethod2 = StaticFactoryMethod.getNewInstance(); System.out.println("staticFactoryMethod == staticFactoryMethod2 :" + (staticFactoryMethod == staticFactoryMethod2) ); }
세번째, 반환 타입의 하위 타입객체를 반환할 수 있다.
반환할 객체의 타입을 자유롭게 선택할 수 있는 유연성으로 구현할 클래스 공개없이
그 객체를 반환할 수 있는 장점이 있다. 예컨대 자바 컬렉션프레임워크는 핵심 인터페이스들에
수정 불가나 동기화 등의 기능을 덧붙여 유틸리티적인 구현체를 제공하는데 이 구현체 대부분을
하나의 인스턴스화 불가 클래스인 java.util.Collections 에서 정적 팩터리 메서드를 통해 얻도록
구현햿다.public abstract class StaticFactoryMethod { abstract void getName(); static public StaticFactoryMethod getNewInstance( String code ) { StaticFactoryMethod staticFactoryMethod = null; if( code.indexOf("2") == 1 ) { staticFactoryMethod = new Point(); } else { staticFactoryMethod = new Coupon(); } return staticFactoryMethod; } } class Coupon extends StaticFactoryMethod { public void getName() { System.out.println("쿠폰을 발행합니다."); } } class Point extends StaticFactoryMethod { public void getName() { System.out.println("포인트 1000점을 적립합니다."); } } public static void main(String args[]){ StaticFactoryMethod staticFactoryMethod = StaticFactoryMethod.getNewInstance("223123"); StaticFactoryMethod staticFactoryMethod1 = StaticFactoryMethod.getNewInstance("123123"); staticFactoryMethod.getName(); staticFactoryMethod1.getName(); }
네번째, 입력 파라미터의 따라 다른 클래스의 객체를 반환 할 수 있다.
EnumSet 클래스는 public 생성자 없이 오직 정적 팩터리 메서드을 통해서만 객체를 반환한다.
원소의 수에 따라 64개 이하면 RecularEnumSet의 객체, 65개 이상이면 JunboEnumSet의 객체를
반환한다. 클라이언트는 이 객체를 알수도 알 필요도 없다.public abstract class StaticFactoryMethodType { public abstract void getName(); static public StaticFactoryMethodType getNewInstance( String code ) { return new OneClass(); } static public StaticFactoryMethodType getNewInstance( String code, String name ) { return new TwoClass(); } } class OneClass extends StaticFactoryMethodType { public void getName() { System.out.println("쿠폰을 발행합니다."); } } class TwoClass extends StaticFactoryMethodType { public void getName() { System.out.println("포인트 1000점을 적립합니다."); } } public static void main(String args[]){ StaticFactoryMethodType isOneObj = StaticFactoryMethodType.getNewInstance("code"); StaticFactoryMethodType isTwoObj = StaticFactoryMethodType.getNewInstance("code","name"); isOneObj.getName(); isTwoObj.getName(); }
다섯번째, 정적 팩터리 메서드 작성 시점에서는 해당 클래스가 존재하지 않아도 된다.
대표적으론 JDBC가 있다.
public static void main(String[] args) { String url = "jdbc:oracle:thin:@localhost:1521:xe"; String sql = "select * from employees"; Connection conn = null; java.sql.Statement st = null; //DB와 소통하는 통로 ResultSet rs = null; //결과 받아서 처리할때 try { Class.forName("oracle.jdbc.driver.OracleDriver"); System.out.println("driver load 성공!"); conn = DriverManager.getConnection(url, "hr", "hr"); System.out.println("DB 연결 성공!"); st = conn.createStatement(); rs = st.executeQuery(sql); //쿼리 실행 후 데이터들이 rs 저장 while(rs.next()){ //한건씩 처리 int empid = rs.getInt(1); //첫번째 칼럼 조회 String fname = rs.getString("first_name"); //컬럼이름도 지정 가능 int sal = rs.getInt("salary"); Date hireDate = rs.getDate("hire_date"); System.out.println(empid+ "\t" + fname + "\t" + sal + "\t" + hireDate); } } catch (ClassNotFoundException e) { System.out.println("driver load 실패!"); e.printStackTrace(); } catch (SQLException e) { System.out.println("DB 연결 실패!"); e.printStackTrace(); } finally { try { if(rs != null) rs.close(); if(st != null) st.close(); if(conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }
'JAVA' 카테고리의 다른 글
생성자에 매개변수가 많다면 빌더를 고려하라. (0) | 2022.07.24 |
---|---|
자바 커스텀 어노테이션 만들기 (0) | 2020.08.02 |
[JAVA]자바 예외 발생시키기 (0) | 2020.06.21 |