이번 글은 추상 팩토리 패턴에 관하여 작성한 글이다.
추상 팩토리 패턴(Abstract factory pattern)은 다양한 구성 요소 별로 '객체의 집합'을 생성해야 할 때 유용하다. 이 패턴을 사용하여 상황에 알맞은 객체를 생성할 수 있다.
위키백과 - 추상 팩토리 패턴
팩토리 메서드 패턴
조건에 따른 객체 생성을 팩토리 클래스로 위임하여, 팩토리 클래스에서 객체를 생성하는 패턴
하나의 팩토리 클래스가 인풋으로 들어오는 값에 따라 if-else || switch 문을 사용해 다양한 서브클래스를 리턴하는 형식으로 구현하였다.
추상 팩토리 패턴
서로 관련이 있는 객체들을 함께 묶어 팩토리 클래스로 만들고, 이들 팩토리를 조건에 따라 생성항도록 다시 팩토리를 만들어서 객체를 생성하는 패턴
추상 팩토리 패턴은 서브 클래스를 생성하는데 있어 이런 if-else 문을 걷어낸다.
추상 팩토리 패턴은 인풋으로 서브클래스에 대한 식별 데이터를 받는 것이 아닌 또 하나의 팩토리 클래스를 받는다.
👉🏼 추상 팩토리 패턴은 팩토리 메서드 패턴을 조금 더 캡슐화한 방식이라고 볼 수 있다.
public abstract class Computer {
public abstract String getRAM();
public abstract String getCPU();
public abstract String getHDD();
@Override
public String toString() {
return "RAM = " + this.getRAM()+", HDD = "+ this.getHDD()", CPU=" this.getCPU();
}
}
public class PC extends Computer {
private String ram;
private String hdd;
private String cpu;
public PC(String ram, String hdd, String cpu) {
this.ram = ram;
this.hdd = hdd;
this.cpu = cpu;
}
@Override
public String getRAM() {
return this.ram;
}
@Override
public String getHDD() {
return this.hdd;
}
@Override
public String getCPU() {
return this.cpu;
}
}
public class Server extends Computer {
private String ram;
private String hdd;
private String cpu;
public PC(String ram, String hdd, String cpu) {
this.ram = ram;
this.hdd = hdd;
this.cpu = cpu;
}
@Override
public String getRAM() {
return this.ram;
}
@Override
public String getHDD() {
return this.hdd;
}
@Override
public String getCPU() {
return this.cpu;
}
}
팩토리 패턴과 방식이 같고
먼저 추상 팩토리의 역할을 하는 인터페이스 또는 추상 클래스가 필요하다
public interface ComputerAbstractFactory {
public Computer createComputer();
}
이 예제에서 키포인트는 작성한 팩토리 인터페이스의 createComputer() 메서드의 리턴 타입이 super class 인 Computer 라는 것이다.
이제 이 팩토리 인터페이스를 구현하는 클래스에서 createComputer() 메서드를 오버라이딩 하여 각각의 서브 클래스를 리턴해줄 것이다.
자바의 다형성을 활용한 방식
public class PCFactory implements ComputerAbstractFactory {
private String ram;
private String hdd;
private String cpu;
public PCFactory(String ram, String hdd, String cpu) {
this.ram = ram;
this.hdd = hdd;
this.cpu = cpu;
}
@Override
public Computer createComputer() {
return new PC(ram, hdd, cpu);
}
}
public class ServerFactory implements ComputerAbstractFactory {
private String ram;
private String hdd;
private String cpu;
public ServerFactory(String ram, String hdd, String cpu) {
this.ram = ram;
this.hdd = hdd;
this.cpu = cpu;
}
@Override
public Computer createComputer() {
return new Server(ram, hdd, cpu);
}
}
public class ComputerFactory {
public static Computer getComputer(ComputerAbstractFactory factory) {
return factory.createComputer();
}
}
이제 ComputerFactory 클래스의 getComputer()라는 static 메서드에 앞서 구현한 PCFactory 나 ServerFactory 인스턴스를 넣어줌으로써 if-else 없이도 각각 원하는 서브 클래스의 인스턴스를 생성할 수 있다.
public class AbstractFactoryTest {
public static void main(String[] args) {
Computer pc = ComputerFactory.getComputer(new PCFacotry("2GB","500GB","2.4GHz"));
Computer server = ComputerFactory.getComputer(new ServerFactory("16GB","1TB","2.9GHz"));
System.out.println("AbstractFactory PC Config::"+ pc);
System.out.println("AbstractFactory Server Config::" + server);
}
출력값
AbstractFactory PC Config::RAM= 2 GB, HDD=500 GB, CPU=2.4 GHz
AbstractFactory Server Config::RAM= 16 GB, HDD=1 TB, CPU=2.9 GHz
추상 팩터리 패턴은 구현보다는 인터페이스를 위한 코드 접근법을 제공한다
위 코드에서 getComputer() 메서드는 파라미터로 인터페이스를 받아 처리하기 때문에 getComputer()에서 구현할 것이 복잡하지 않다.
추상 팩토리 패턴은 추후 서브 클래스를 확장하는 데 있어 굉장히 쉽게할 수 있다.
만약 Mac 클래스를 추가하고자 하면 getComputer()의 수정 없이 MacFactory만 작성해주면 된다.
팩토리 패턴의 조건문으로부터 자유롭다.
https://readystory.tistory.com/119
https://ko.wikipedia.org/wiki/%EC%B6%94%EC%83%81_%ED%8C%A9%ED%86%A0%EB%A6%AC_%ED%8C%A8%ED%84%B4