팩토리 메서드 패턴은 객체를 동적으로 생성하는데 정형화된 객체지향 디자인 패턴이다. 객체를 생성하는 코드를 클라이언트 코드와 분리하여 객체를 생성하고 반환한다. 클라이언트 코드는 객체생성에 대한 복잡한 코드를 이해할 필요없이 단순화된 인터페이스로 상호작용한다.
클라이언트 코드란?
다른 모듈이나 라이브러리, 클래스 등을 사용하는 코드를 일컫는다.
구조는 팩토리 클래스를 추상클래스로 선언한다. 팩토리아이템이라는 이름의 클래스가 상속하게 하고 이를 이용해 아이템 인터페이스를 상속받은 구현 클래스를 생성한다.
팩토리 메서드는 부모 클래스에서 객체들을 생성할 수 있는 인터페이스를 제공하지만, 자식 클래스들이 생성될 객체들의 유형을 변경할 수 있도록 하는 생성 패턴입니다.
출처 https://refactoring.guru/ko/design-patterns/factory-method
package designpattern;
public abstract class Factory {
public Item create(String name) {
boolean canMakeItem = this.isCreatable(name);//name이 들어와 hashmap키로 itemData value를 찾고 itemData의 current가 maxCount보다 작으면 true 반환
if(canMakeItem) {
Item item = this.createItem(name);//
postprocessItem(name);
return item;
}
return null;
}
public abstract boolean isCreatable(String name);
public abstract Item createItem(String name);
public abstract void postprocessItem(String name);
}
팩토리 추상클래스이다. 이것을 상속받아 특정 유형의 아이템을 생성하는 팩토리아이템 클래스를 만든다. 추상 메서드 같은 경우 구현되어있지 않지만 create메서드에 이미 자리를 잡고 있다.
FactoryItem클래스에서 추상클래스들을 구현하면 비로소 create메서드는 동작한다. 상속받은 자식 클래스에서 어떻게 구현하는가에 따라서 create메서드는 다른 과정을 거쳐서 return한다.
public class FactoryItem extends Factory{
private HashMap<String,ItemData> repository = new HashMap<>();
private class ItemData {//maxCount와 currentCount를 가지고 있고 FactoryItem안에서 객체를 생성한 다음 두 값을 비교하는 역할
int maxCount;
int currentCount;
ItemData(int maxCount){
this.maxCount = maxCount;
}
}
@Override
public boolean isCreatable(String name) {
ItemData itemData = repository.get(name);//map컬렉션에서 name이라는 String 키값을 이용해 ItemData타입의 value를 리턴받고 itemData참조변수에 대입한다.
if(itemData == null) {//name의 value값이 null일 경우 이 if문이 출력
System.out.println(name + "은 알 수 없는 아이템입니다.");
return false;
}
if(itemData.currentCount >= itemData.maxCount) {//itemData클래스 객체의 currentCount와 maxCount를 비교
System.out.println(name+"은 품절 아이템입니다.");
return false;
}
return true;//maxCount값이 더 높으면 true출력
}
@Override
public Item createItem(String name) { //string값이 들어오면 그 값에 맞는 객체를 생성함
Item item = null;
if(name.equals(null)) name = Main.kb.next();
if(name.equals("Strawberry")) item = new Strawberry();
if(name.equals("Carrot")) item = new Carrot();
if(name.equals("Tomato")) item = new tomato();
return item;
}
@Override
public void postprocessItem(String name) {
ItemData itemData = repository.get(name);//repository hashmap 컬렉션에서 키값으로 String을 입력해 itemData value를 리턴함
if(itemData != null) itemData.currentCount++;//currentCount값을 증가시킴 hashmap 키값으로 itemData타입의 객채 value가 들어있었다면
}
public FactoryItem() {
repository = new HashMap<String, ItemData>();
repository.put("Strawberry", new ItemData(3));//maxCount값을 초기화
repository.put("Carrot", new ItemData(2));
repository.put("Tomato", new ItemData(4));
}
}
팩토리아이템을 통해서 HashMap 컬렉션안에 클래스를 생성하고 maxCount를 생성자로 초기화한다.
public interface Item {
void use();
}
public class Strawberry implements Item{
@Override
public void use() {
System.out.println("딸기딸기");
}
}
public class tomato implements Item{
@Override
public void use() {
System.out.println("토마토");
}
}
public class Carrot implements Item{
@Override
public void use() {
System.out.println("당근");
}
}
세가지 클래스를 구현하고 이들은 FactoryItem에 의해 생성되고 사용된다.