본문 바로가기
개발자 일지/Java

[디자인패턴]팩토리 메소드 패턴(Factory Method Pattern)

by 네빌링 2021. 3. 7.
반응형

-디자인 패턴 중 인스턴스 생성 여부를 팩토리 클래스에서 결정하는 팩토리 메소드 패턴을 알아본다.


팩토리 메소드 패턴이란?

인스턴스 생성을 팩토리 클래스라는 인스턴스 생성 전용 클래스를 만들어 필요에 맞게 인스턴스를 생성하는 방식이다. 인스턴스를 사용하는 클라이언트 및 어플리케이션 쪽에서 직접 생성하는 것이 아니라, 인스턴스를 생성하는 구체적인 클래스를 이용하여 따로 생성하는 것이다.

이렇게 하면 인스턴스 생성에 대한 내용이 바뀌더라도 팩토리 클래스만 수정하면 되기 때문에 객체지향적으로 설계할 수 있고 클래스 간의 결합도가 낮아져서 유지보수에도 효율적이다.

예제 내용

예제는 나이에 따른 처방 시스템을 변경하는 예제이다. 나이에 따라 baby, children, adult, oldman 타입으로 구분하여 이에 맞게 처방시스템을 실행하도록 한다.

 

우선 팩토리 메소드 패턴 적용 전후 공통으로 사용하는 처방 인터페이스를 먼저 만들고 이를 상속한 각각의 처방시스템을 구현한다.

 

package FactoryMethod;

public interface Medicine {
	public void makeMedicine();
}
package FactoryMethod;

public class BabyMedicine implements Medicine {
	@Override
	public void makeMedicine() {
		System.out.println("베이비 전용 약을 만들었습니다");
	}

}
package FactoryMethod;

public class ChildrenMedicine implements Medicine {
	@Override
	public void makeMedicine() {
		System.out.println("어린이 전용 약을 만들었습니다");
	}

}
package FactoryMethod;

public class OldmanMedicine implements Medicine{
	@Override
	public void makeMedicine() {
		System.out.println("노인 전용 약을 만들었습니다.");
	}
}

 

위와 같이 처방시스템을 나이대별로 만들었다.

 

팩토리 메소드 패턴 적용 전 예제

위의 처방시스템을 팩토리 메소드 적용 전 사용해본다.

 

package WithoutFactoryMethod;

public class RequestPrescription {
	public static void main(String[] args) {
		Medicine medicine;
		
		medicine = new BabyMedicine();
		medicine.makeMedicine();
		medicine = new ChildrenMedicine();
		medicine.makeMedicine();
		medicine = new AdultMedicine();
		medicine.makeMedicine();
		medicine = new OldmanMedicine();
		medicine.makeMedicine();
		
		//ChildrenMedicine의 처방시스템이 너무 구식이라 사용할 수 없어서 변경 후 NewChildrenMedicine 인스턴스로 변경해야 한다면..
		//ChildrenMedicine을 사용하는 모든 곳을 변경해주어야 함(RequestPrescription이 버전별로 1000개가 있다면?1000개의 부분을 수정해줘야 함)
		//유지보수가 어렵고 확장에는 열려있고 수정에는 닫혀있는 객체지향 원칙에 위배됨
	}
}

//결과
//베이비 전용 약을 만들었습니다
//어린이 전용 약을 만들었습니다
//어른 전용 약을 만들었습니다
//노인 전용 약을 만들었습니다.

 

위와 같이 처방요청 어플리케이션(RequestPrescription)에서 처방시스템을 각각 사용하기 위해 인스턴스를 만들어줬다. 그런데 ChildrenMedicine() 시스템이 구식이라 NewChildrenMedicine() 시스템으로 변경해야 한다면 직접적으로 처방요청 어플리케이션을 건드려야 한다. 또한 이 처방요청 어플리케이션이 여러개라면 여러 곳을 수정해야 한다. 수정에 닫혀있어야 한다는 객체지향 원칙을 위배하게 되는 것이다.

 

이를 해결하기 위해 팩토리 메소드 패턴을 적용해보자.

 

팩토리 메소드 패턴 적용 예제

다음과 같이 인스턴스 생성을 위임하기 위해 팩토리 메소드 클래스를 만들었다.

 

package FactoryMethod;

public class PrescriptionFactory {
	Medicine medicine;
	
	//인스턴스 생성을 위한 '팩토리 메소드'
	public Medicine prescribe(Type type) {
		switch (type) {
			case BABY:
				medicine = new BabyMedicine();
				break;
			case CHILDREN:
				medicine = new ChildrenMedicine();
				break;
			case ADULT:
				medicine = new AdultMedicine();
				break;
			case OLDMAN:
				medicine = new OldmanMedicine();
				break;
		}
		
		return medicine;
	}
	
	public void checkPrescribe() {
		medicine.makeMedicine();
	}
}

//인스턴스 생성을 결정하기 위한 enum class
enum Type {
	BABY,CHILDREN,ADULT,OLDMAN;
}

 

 

어플리케이션에서는 enum으로 만든 Type만 넘겨준다.

 

 

package FactoryMethod;

public class RequestPrescription {
	public static void main(String[] args) {
		//팩토리메소드 패턴을 사용하여 구체적인 인스턴스 생성 방식을 Factory에 위임
		PrescriptionFactory factory = new PrescriptionFactory();
		
		//팩토리메소드인 prescribe에 구체적인 인스턴스 생성방식 설정(BABY)
		factory.prescribe(Type.BABY);
		//생성여부 체크
		factory.checkPrescribe();
		
		//팩토리메소드인 prescribe에 구체적인 인스턴스 생성방식 설정(CHILDREN)
		factory.prescribe(Type.CHILDREN);
		//생성여부 체크
		factory.checkPrescribe();
		
		//팩토리메소드인 prescribe에 구체적인 인스턴스 생성방식 설정(ADULT)
		factory.prescribe(Type.ADULT);
		//생성여부 체크
		factory.checkPrescribe();
		
		//팩토리메소드인 prescribe에 구체적인 인스턴스 생성방식 설정(OLDMAN)
		factory.prescribe(Type.OLDMAN);
		//생성여부 체크
		factory.checkPrescribe();
	}
}

//결과
//베이비 전용 약을 만들었습니다
//어린이 전용 약을 만들었습니다
//어른 전용 약을 만들었습니다
//노인 전용 약을 만들었습니다.

 

위와 같이 처방시스템의 인스턴스 생성을 PrescriptionFactory라는 팩토리클래스에 넘겨주었다. 여기서 prescribe(Type type)이 바로 팩토리 메소드이다.

이제 ChildrenMedicine()을 수정해야 하더라도 어플리케이션 쪽에서 수정할 필요 없이 팩토리 메소드만 수정해주면 이를 사용하는 모든 곳에 적용이 될 수 있다.

 

 

반응형