Language/Java

팩토리 메서드 패턴과 Java Reflection

kimjingyu 2023. 9. 15. 17:45
728x90

싱글톤 패턴

  1. private 생성자를 만든다. 즉, 외부에서 인스턴스를 생성하지 못하게 한다.
  2. 자기 자신 인스턴스를 참조하는 static한 필드를 선언한다.
  3. 2번에서 생성한 인스턴스를 반환하는 static한 메서드를 만든다.
public class BeanFactory {
    // 2. 자기 자신 인스턴스를 참조하는 static한 필드를 선언한다.
    private static BeanFactory instance = new BeanFactory();

    // 1. private 생성자를 만든다. 즉, 외부에서 인스턴스를 생성하지 못한다.
    private BeanFactory() {
    }

    // 3. 2번에서 생성한 인스턴스를 반환하는 static한 메서드를 만든다.
    public static BeanFactory getInstance() {
        return instance;
    }
}

 

팩토리 메서드 패턴

객체가 생성되는 과정을 숨겨주는 패턴. 즉, 복잡한 생산 과정을 숨기고, 완성된 인스턴스만 반환하는 것이다.

다르게 말하면 객체 생성을 대신해주는 패턴이라고 할 수 있다.

public Bus getBus() {
    return new Bus();
}

 

ClassLoader를 이용한 인스턴스 생성하기. Java Reflection

a()라는 메서드를 가지 클래스가 여러 개 있다. 그리고 현재 사용하고자 클래스 이름이 무엇인지 아직 모른다. 클래스 이름은 나중에 알려준다. 이때, a() 메서드를 실행할 수 있도록 코드를 작성하라.

 

JVM은 클래스를 CLASSPATH에서 찾는다. 이때, 다음 코드는 Class.forName(className)은 className에 해당되는 클래스를 CLASSPATH에서 찾는다. 그리고 그 클래스 정보를 Class clazz 참조 변수에 넣어준다.

String className = "theory.singleton.Bus";
Class<?> clazz = Class.forName(className);
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
    System.out.println("method = " + method.getName());
}

 

그리고 다음 세 줄의 코드는 Object o = new Bus(); 와 같다. 여기서 clazz.newInstance()는 clazz 정보를 가지고 새로운 인스턴스를 만들라는 의미이다.

String className = "theory.singleton.Bus";
Class<?> clazz = Class.forName(className);
Object o = clazz.newInstance();

 

즉, 인스턴스를 만드는 과정을 new 연산자를 사용하지 않고 인스턴스를 생성한 것이다. 그리고 이 것을 형변환해서 다음과 같이 사용할 수 있다.

String className = "theory.singleton.SuperCar";
Class<?> clazz = Class.forName(className);
Object o = clazz.newInstance();
Car car = (Car) o;
car.a();

 

그리고 만약 Car를 상속하지 않는 다른 클래스의 메서드를 실행시키고자 하면 다음과 같이 코드를 작성할 수 있다.

여기서 clazz.getDeclaredMethod의 의미는 a() 메서드 정보를 가지고있는 Method를 반환하라는 의미이고, m.invoke(o, null)의 의미는 Object o 가 참조하는 객체의 m 메서드를 실행하라는 의미이다.

String className = "theory.singleton.SuperCar";
Class<?> clazz = Class.forName(className);
Object o = clazz.newInstance();

Method method = clazz.getDeclaredMethod("a", null);
method.invoke(o, null);

 

이렇게 하면 문자열로 클래스 이름과 메서드 이름을 받아들여서 인스턴스를 생성해 실행할 수 있게 된 것이다.

 

이렇게 ClassLoader를 이용해 인스턴스를 만들 수도 있고, 그 인스턴스가 가진 메서드를 실행할 수 있는 것을 자바에서는 Reflect라는 문법이라 한다.

 

그리고 스프링, 서블릿이 내부적으로 Reflection이 사용된다.

 

또한 이 팩토리 메서드 패턴과 ClassLoader를 결합하면 클래스 이름만 가지고도 인스턴스를 만들어주는 공장을 만들어줄 수 있는 것이다. 즉, 인스턴스 생성이 필요하면 그 공장에 요청만 하면 되는 것이다.

 

인용

https://youtu.be/8A6ElEmMnSY?si=zoTjP0wZVl49igYT 

 

728x90