이전에 학습했던 Factory Method Pattern이 객체의 생성 책임을 추상 클래스 or 인터페이스(=Factory)에 맡겼던 패턴이라면 Abstract Factory Pattern
은 객체의 생성 책임을 사용하는 입장에 맡긴 패턴이라고 생각하면 될거 같다.
말로 해서는 이해가 어렵다! 직접 패턴 코드를 보고 다시 이해해보자!
public interface IPhonePartsFactory {
Chip createChip();
Camera createCamera();
}
public interface Chip {
String name();
}
public interface Camera {
String name();
}
다음과 같이 기본 뼈대가 될 IPhonePartsFactory
Chip
Camera
를 먼저 정의해준다. 아이폰을 만들기 위해 Chip과 Camera를 파츠로 넣어야하고 각각의 파츠를 구현해서 넣어줄 것이다.
그리고 아이폰은 Plus
Pro
ProMax
버전만 있다고 가정하고 진행해보려고 한다!
chip과 camera를 구현해보자
public class PlusCamera implements Camera{
@Override
public String name() {
return "Plus Camera";
}
}
public class PlusChip implements Chip{
@Override
public String name() {
return "Plus Chip";
}
}
plus 라인의 부품들을 모두 만들어냈다.
이제 아이폰 제조 구현체를 정의해보자.
public class IPhonePlusFactory implements IPhonePartsFactory{
@Override
public Chip createChip() {
return new PlusChip();
}
@Override
public Camera createCamera() {
return new PlusCamera();
}
}
plus 제조 구현체까 모두 정의를 완료했다!
이제 우리는 아이폰 Plus 주문만 넣어주면 된다!
public class IPhone {
private Camera camera;
private Chip chip;
public Camera getCamera() {
return camera;
}
public void setCamera(Camera camera) {
this.camera = camera;
}
public Chip getChip() {
return chip;
}
public void setChip(Chip chip) {
this.chip = chip;
}
}
먼저 아이폰을 제조해야하니 아이폰 자체를 만들어주었다.
public class IPhoneOrderFactory {
private IPhonePartsFactory iPhonePartsFactory;
public IPhoneOrderFactory(IPhonePartsFactory iPhonePartsFactory) {
this.iPhonePartsFactory = iPhonePartsFactory;
}
public IPhone createIPone(){
IPhone iPhone = new IPhone();
iPhone.setCamera(iPhonePartsFactory.createCamera());
iPhone.setChip(iPhonePartsFactory.createChip());
return iPhone;
}
}
핵심
여기 부분이 핵심인데 주문이 들어오는 구현체가 어떤 구현체인지 따라 반환해주는 아이폰의 버전이 변경될 부분이다.
public class Client {
public static void main(String[] args) {
IPhoneOrderFactory iPhoneOrderFactory = new IPhoneOrderFactory(new IPhonePlusFactory());
IPhone iPhone = iPhoneOrderFactory.createIPone();
System.out.println(iPhone.getCamera().getClass());
System.out.println(iPhone.getChip().getClass());
}
}
주문을 해보면
다음과 같이 아이폰이 잘 제조된 것을 확인해볼 수 있다.
public class ProCamera implements Camera{
@Override
public String name() {
return "Pro Camera";
}
}
public class ProChip implements Chip{
@Override
public String name() {
return "Pro Chip";
}
}
public class ProMaxCamera implements Camera{
@Override
public String name() {
return "Pro Max Camera";
}
}
public class ProMaxChip implements Chip{
@Override
public String name() {
return "Pro Max Chip";
}
}
plus, pro, pro max 라인의 부품들을 모두 만들어냈다.
public class IPhoneProFactory implements IPhonePartsFactory{
@Override
public Chip createChip() {
return new ProChip();
}
@Override
public Camera createCamera() {
return new ProCamera();
}
}
public class IPhoneProMaxFactory implements IPhonePartsFactory{
@Override
public Chip createChip() {
return new ProMaxChip();
}
@Override
public Camera createCamera() {
return new ProMaxCamera();
}
}
plus, pro, pro max 제조 구현체까 모두 정의를 완료했다!
이제 우리는 고객이 원하는 아이폰 종류에 따라 주문만 넣어주면 된다!
public class Client {
public static void main(String[] args) {
IPhoneOrderFactory iPhoneOrderFactory1 = new IPhoneOrderFactory(new IPhonePlusFactory());
IPhoneOrderFactory iPhoneOrderFactory2 = new IPhoneOrderFactory(new IPhoneProFactory());
IPhoneOrderFactory iPhoneOrderFactory3 = new IPhoneOrderFactory(new IPhoneProMaxFactory());
IPhone iPhone1 = iPhoneOrderFactory1.createIPone();
IPhone iPhone2 = iPhoneOrderFactory2.createIPone();
IPhone iPhone3 = iPhoneOrderFactory3.createIPone();
System.out.println(iPhone1.getCamera().getClass());
System.out.println(iPhone1.getChip().getClass());
System.out.println(iPhone2.getCamera().getClass());
System.out.println(iPhone2.getChip().getClass());
System.out.println(iPhone3.getCamera().getClass());
System.out.println(iPhone3.getChip().getClass());
}
}
결과를 확인해보면 알맞은 부품들이 사용된 것을 확인할 수 있고
public class Client {
public static void main(String[] args) {
IPhoneOrderFactory iPhoneOrderFactory1 = new IPhoneOrderFactory(new IPhonePlusFactory());
IPhoneOrderFactory iPhoneOrderFactory2 = new IPhoneOrderFactory(new IPhoneProFactory());
IPhoneOrderFactory iPhoneOrderFactory3 = new IPhoneOrderFactory(new IPhoneProMaxFactory());
IPhone iPhone1 = iPhoneOrderFactory1.createIPone();
IPhone iPhone2 = iPhoneOrderFactory2.createIPone();
IPhone iPhone3 = iPhoneOrderFactory3.createIPone();
System.out.println(iPhone1.getCamera().name());
System.out.println(iPhone1.getChip().name());
System.out.println(iPhone2.getCamera().name());
System.out.println(iPhone2.getChip().name());
System.out.println(iPhone3.getCamera().name());
System.out.println(iPhone3.getChip().name());
}
}
우리가 구현한 기능으로 확인해 보면
동일하게 잘 나오는 것을 확인할 수 있다.
여기서 우리는 디자인 패턴의 힘을 느낄 수 있는데. 우리가 아이폰 생산 라인을 늘리면서
확장
을 했지만 실제 IPone 관련 코드가수정된 곳은 없다
라는 점이다.(=OCP) 또한 생성자에 넣어주는 구현체마다 자신의 책임만을 갖고 있기 때문에 SRP를 지켰다고도 볼수 있다.(개인의 생각에 따라 의견이 다를 수 있음!)
앞서 말했던 Factory Method Pattern과의 차이점을 다시 짚어보려고 한다. 우선 Factory Method Pattern의 코드를 잠깐만 보면
public class Client {
public static void main(String[] args) {
Car car1 = new AvanteFactoryV2().orderCar("최준호", "white");
Car car2 = new GV80FactoryV2().orderCar("최준호", "white");
}
}
다음과 같이 구체적인 Factory를 가지고 객체를 생성해온다.
그에 반해
public class Client {
public static void main(String[] args) {
IPhoneOrderFactory iPhoneOrderFactory1 = new IPhoneOrderFactory(new IPhonePlusFactory());
IPhoneOrderFactory iPhoneOrderFactory2 = new IPhoneOrderFactory(new IPhoneProFactory());
IPhoneOrderFactory iPhoneOrderFactory3 = new IPhoneOrderFactory(new IPhoneProMaxFactory());
IPhone iPhone1 = iPhoneOrderFactory1.createIPone();
IPhone iPhone2 = iPhoneOrderFactory2.createIPone();
IPhone iPhone3 = iPhoneOrderFactory3.createIPone();
}
}
Abstract Factory Pattern의 경우 사용하려고 하는 입장에서 내가 어떤 부품으로 조립하고 싶은지 구현체를 짚어 넣어줘야 한다는 차이점이 있다.
이 둘은 거의 비슷해 보이지만
구체적인 구현체로 직접 객체를 반환해주느냐
혹은
주입된 구현체에 따라 객체를 반환해주느냐
차이점이라고 이해하면 될거 같다!