본문 바로가기

Backend/Java

자바 팩토리 메소드 패턴 (Java Factory Method Pattern)

팩토리 메소드 패턴에 대해서 알아볼게요.

굉장히 많이 쓰이는 패턴이고, 익혀두면 나름 유용하게 쓸 수 있어요.

자바 소스 안에서도 많이 볼 수 있구요.

저도 때때로 사용하는 것 같습니다.

 

예제로는 패스워드를 암호화하는 기능을 구현해볼거에요.

실제 암호화 로직은 뺄거구요.

최대한 완성도 높게 구조를 만들겠습니다.

1. 인터페이스 만들기

Password라는 인터페이스를 만들었고, 클래스에서 세부 구현할 encode라는 메소드를 추가했어요.

혹은 추상클래스를 만들어서 추상 메소드를 추가하셔도 상관없습니다.

 

public interface Password {
	
	String encode(String str);

}

2. 구현체 작성

라이트하게 암호화하는 SimplePassword 클래스

강하게 암호화하는 SuperPassword 클래스를 만들었습니다.

 

public class SimplePassword implements Password {

	@Override
	public String encode(String str) {
		return "간단하고 빠릅니다.";
	}

}

 

public class SuperPassword implements Password {

	@Override
	public String encode(String str) {
		return "절대 뚫리지 않습니다.";
	}

}

3. 타입 관리 (enum)

그리고 PasswordType이라는 enum 클래스를 만들어서 어떤 유형의 Password를 제공할지 관리하도록 했어요.

타입만 보고 어떤 유형의 Password가 있는지 한 눈에 확인할 수 있어요.

주석도 여기다가 적어주는 것이 좋습니다.

다만, 구현체가 추가될 경우 여기도 맞춰서 추가해줘야한다는 단점이 존재합니다.

 

public enum PasswordType {

	/**
	 * 패스워드를 간단하고 빠르게 암호화합니다.
	 */
	SIMPLE, 
	
	/**
	 * 패스워드를 복잡하고 강력하게 암호화합니다.
	 */
	SUPER

}

4. 팩토리 클래스

인스턴스를 생성하여 리턴하는 클래스에요.

이게 팩토리 메서드 패턴의 핵심이에요.

항상 확장할 때는 Factory 클래스를 먼저 확인하고, 무엇을 추가해야 하는지를 파악하는 것이 굉장히 중요합니다!

Factory 클래스는 아주 다양한 형태로 구현할 수 있어요.

아주 간단한 예제이기 때문에 static 메소드로 객체를 생성했습니다.

 

public class PasswordFactory {

	static Password build(PasswordType type) {
		switch (type) {
		case SIMPLE:
			return new SimplePassword();
		case SUPER:
			return new SuperPassword();
		default:
			return null;
		}
	}

}

5. 사용 방법

Password password = PasswordFactory.build(PasswordType.SIMPLE);
String enc = password.encode("");
System.out.println(enc);

 

유형을 교체하거나 추가하고 싶을 때 PasswordType을 확인하면 머가 있는지 알 수 있고,

enum에 주석을 달아놔서 굳이 클래스에 안들어가도 내용 확인이 가능합니다.

 

 

알려진 가장 큰 목적은 Factory에 객체 생성의 역할을 담당하게 하는 것입니다.

특히, 객체 생성 시에 공통적으로 처리해야 할 로직이 있을 때 효과가 있어요.

 

케바케지만, 패턴을 어느 정도 이해하고 익숙한 사람에게는 재사용하기 좋은 패턴인 것 같아요.

다른 사람이 와서 보면 프레임워크 유틸로 착각할 정도로 완성도가 높아집니다.

 

주의해야 하는 경우는, 구현 클래스 안에서 인터페이스 메소드를 @Override하지 않고 단독으로 메소드를 추가해서 쓰는 일이 생길 가능성이 있다면 팩토리 메소드 패턴을 쓰면 낭패입니다.

인터페이스를 타입으로 하는 인스턴스를 사용하면 구현체에서 별도로 추가한 메소드를 사용할 수 없기 때문이죠.

 

또한, 아무데나 남발하면 복잡도만 높아질 수 있으니 충분히 고려하고 사용하는 것이 중요하겠습니다.