본문 바로가기
[즐거운 자바 강좌] 정리

[즐거운 자바 강좌] 섹션4 - 팩토리 메소드(Factory Method) 패턴

by haeyoon 2024. 3. 31.

팩토리 메소드 패턴이란?

복잡한 생산 과정을 숨기고, 완성된 인스턴드만 반환한다.

 

[new를 사용하지 않고도 클래스 이름만 가지고도 인스턴스 생성하는 방법]

1) 팩토리 사용

package com.example;

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(){ //내부에서 Bus 만들어서 return
        return new Bus();
    }
}

getBus() 생성

package com.example;

public class BeanFactoryMain {
    public static void main(String[] args) {
        BeanFactory bf1 = BeanFactory.getInstance();
        BeanFactory bf2 = BeanFactory.getInstance();

        Bus b1 = bf1.getBus();
        Bus b2 = bf2.getBus(); //생성과정을 맡김
        //기존에는 Bus b3 = new Bus();로 생성
    }
}

생성 과정을 대신해주는 클래스 = 팩토리

 

2) 클래스 로더 사용

Class clazz = Class.forName("클래스풀네임");
Object obj = clazz.newInstance();

[예제]

 a() 메소드를 가지고 있는 클래스가 있다. 이 클래스 이름이 아직 무엇인지 모르지만 나중에 이 클래스 이름을 알려주겠다.
 a()메소드를 실행할 수 있도록 코드를 작성해라.

 

ex) Bus b1 = new Bus(); 
       b1.a();

  에서 Bus인지를 안알려주는것

[단계1]

package com.example;

public class Bus {
    public void a(){
        System.out.println("a");
    }
    public void b(){
        System.out.println("a");
    }
    public void c(){
        System.out.println("a");
    }
}
package com.example;

public class ClassLoaderMain {
    public static void main(String[] args) throws Exception{
        //className에 해당되는 클래스 정보를 CLASSPATH에서 찾음
        //그 정보를 clazz가 참조하도록 한다.
        // Object o = new Bus();
        String className = "com.example.Bus"; //나중에 알게될 클래스 명
        Class clazz = Class.forName(className);
        Object o = clazz.newInstance();

        Bus b = (Bus)o; //Bus로 형변환
        b.a();
    }
}

 

[단계2] a()이름을 가진 메소드를 모두 출력하고 싶을때

추상 클래스 생성

package com.example;

public abstract class Car {
    public abstract void a();

}

 

상속받는 클래스 작성

package com.example;

public class Bus extends Car {
    public void a(){
        System.out.println("a");
    }
    public void b(){
        System.out.println("a");
    }
    public void c(){
        System.out.println("a");
    }
}
package com.example;

public class SuperCar extends Car{
    public void a(){
        System.out.println("supercar a");
    }
}

 

→ Car를 상속받는 메소드는 모두 가능

String ClassName = "come.example.Car를상속받는메소드"

package com.example;

public class ClassLoaderMain {
    public static void main(String[] args) throws Exception{
        // Object o = new Bus();
        // Car c = new Bus();
        String className = "com.example.SuperCar"; // Car을 상속받는 아무 클래스이름. SuperCar & Bus
        Class clazz = Class.forName(className);
        Object o = clazz.newInstance();

        Car b = (Car)o; //인스턴스를 부모타입으로 참조
        b.a();
    }
}

[단계3] Car를 상속받지 않는 클래스 생성

package com.example;

public class MyHome {
    public void a(){
        System.out.println("a라는 메소드를 myhome이 갖고있어요");
    }
}

 

String className = "com.example.아무클래스이름"; 

.getDeclaredMethod를 사용했기때문에 아무거나 사용해도 찾을 수 있음

package com.example;

import java.lang.reflect.Method;

public class ClassLoaderMain {
    public static void main(String[] args) throws Exception{
        String className = "com.example.MyHome"; //나중에 알게될 클래스 명
        Class clazz = Class.forName(className);
        Object o = clazz.newInstance();

        Method m = clazz.getDeclaredMethod("a", null); // a() 메소드 정보를 가지고 있는 Method를 반환하라
        m.invoke(o, null); //Object o가 참조하는 객체의 m 메소드를 실행하라
    }
}