Java/Design Pattern

[디자인 패턴] 생성패턴 - 추상 팩토리 패턴 (Abstract Factory patterns)

민돌v 2023. 2. 9. 10:10
728x90
(인프런) 코딩으로 학습하는 GoF의 디자인 패턴 - 백기선, 강의를 보고 정리한 글입니다.
코드는 GitHub 에 있습니다

 

#1. 객체 생성 관련 패턴

#2. 구조 관련 패턴

 

#3. 행동 관련 패턴

 

 

 


✔️ 추상 팩토리 패턴

  • 추상 팩토리 패턴은 팩토리 메소드 패턴과 팩토리 부분은 매우 유사하지만, 팩토리를 사용하는 Client에게 맞춰져 있습니다.
  • 추상 팩토리 패턴의 목적은 : 팩토리에서 인스턴스를 만들어 사용하는 Client 코드를 인터페이스 기반으로 사용할 수 있도록 도와주도록 하는 것을 목적으로 둡니다.

 

✔️ 추상 팩토리 패턴 vs 팩토리 메서드 패턴

  • 팩토리 메서드 패턴
    • 조건에 따른 객체 생성을 팩토리 클래스로 위임하여, 팩토리 클래스에서 객체를 생성하는 패턴
  • 추상 팩토리 패턴
    • 서로 관련이 있는 객체들을 통째로 묶어서 팩토리 클래스로 만들고, 이들 팩토리를 조건에 따라 생성하도록 다시 팩토리를 만들어서 객체를 생성하는 패턴

 

➡️ 즉, 추상 팩토리 패턴은 팩토리 메소드를 한번 더 추상 팩토리로 묶은 후, 어떤 클래스를 구현할 것인지 클라이언트 코드에서 주입해 구체적언 클래스의 의존성을 최대한 제거한 구조라고 볼 수 있습니다.

이렇게 함으로써 어떤 클래스의 인스턴스를 사용할 것인지 가장 외부에서 호출하는 클라언트에게 내부를 감출 수 있게됩니다.

  • (호출하는 쪽은 구현에 신경쓰지 않고 호출만 하면 된다. → 즉. 느슨한 결합이 가능하다)

 

✔️ 추상 팩토리 패턴 구현 예시

 

1. 먼저 팩토리 패턴때 구현했던 Ship 객체에 부품 anchor 와 wheel 을 맴버변수로 추가합니다.

  • anchor 와 wheel 은 어떤 부품이 들어올지 모르므로, 인터페이스 객체로 구현하였습니다.

Ship.class

@Setter
@Getter
@ToString
public class Ship {

    private String name;
    private String email;
    private String logo;

    //부품 (03 추상 팩토리)
    private AnChore anchor;
    private Wheel wheel;

    public void setAnchor(AnChore anchor) {
        this.anchor = anchor;
    }

    public void setWheel(Wheel wheel) {
        this.wheel = wheel;
    }
}

public interface AnChore {

}

public interface Wheel {

}

 

2. 그 다음 어떤 부품을 선택할것인지 구현의 선택을 담당하는 부품 팩토리를 만들어줍니다.

  • 어떤 부품을 구현할 것인지는 팩토리 메소드 패턴과 같이 하위 구현체가 선택합니다.
public interface ShipPartsFactory {

    AnChore createAnchor();

    Wheel createWheel();
}

public class WhiteShipPartsFactory implements ShipPartsFactory{

    @Override
    public AnChore createAnchor() {
        return new WhiteAnchor();
    }

    @Override
    public Wheel createWheel() {
        return new WhiteWheel();
    }
}

 

3. 그 다음 배를 만드는 ShipFactory 를 interface 로 선언해 줍니다.

  • 구체적으로 ShipFactory 를 구현하는 하위 클래스에서 어떤 부푼객체를 구현할지 외부에서 주입받을 수 있도록 미리 구현해준 ShipPartsFactory interface를 생성자로 주입받습니다.
public interface ShipFactory {

    default Ship orderShip(String name, String email) {
        validate(name, email);
        return createShip();
    }

    Ship createShip();

    private void validate(String name, String email) {
        //validate
       
    }
}

public class WhiteShipFactory implements ShipFactory {

    private ShipPartsFactory shipPartsFactory;

    public WhiteShipFactory(ShipPartsFactory shipPartsFactory) {
        this.shipPartsFactory = shipPartsFactory;
    }

    @Override
    public Ship createShip() {
        Ship ship = new WhiteShip();
        ship.setAnchor(shipPartsFactory.createAnchor());
        ship.setWheel(shipPartsFactory.createWheel());
        return ship;
    }
}

 

4. 이렇게 한다면 클라이언트 쪽에서, 어떤 구현을 원하는지 주입해주기만 하면 되기 팩토리 패턴과 마찬가지로 요구사항이 변경되어도 내부 코드는 변경되지 않고 확장할 수 있는 구조가 되어집니다.

public class ShipInventory {

    public static void main(String[] args) {
        ShipFactory whiteShipFactory = new WhiteShipFactory(new WhiteShipPartsFactory());
        Ship ship = whiteShipFactory.createShip();
        System.out.println("ship.getAnchor().getClass() = " + ship.getAnchor().getClass());
        System.out.println("ship.getWheel().getClass() = " + ship.getWheel().getClass());

        ShipFactory whiteProShipFactory = new WhiteShipFactory(new WhiteShipProPartsFactory());
    }
}

 

 

 


 

✔️ 추상 팩토리 패턴 정리

팩토리 메소드 패턴과 굉장히 흡사한데 무엇이 다른건가.

 

📌 모양과 효과는 둘 다 비슷합니다.

  • 팩토리 메소드 패턴, 추상 팩토리 패턴 둘 다 구체적인 객체 생성 과정을 추상화한 인터페이스를 제공합니다.

 

📌 하지만 보는 관점이 다르다고 합니다.

  • 팩토리 메소드 패턴
    • 팩토리 메소드 패턴은 “팩토리를 구현하는 방법 (inheritance)”에 초점을 둔다. (객체를 만드는 과정을 추상화)
    • 팩토리 메소드 패턴은 구체적인 객체 생성 과정을 하위 또는 구체적인 클래스로 옮기는 것이 목적.
  • 추상 팩토리 패턴
    • 추상 팩토리 패턴은 팩토리를 사용하는 방법 (composition)”에 초점을 둔다. 목적이 조금 다르다.
    • 추상 팩토리 패턴은 관련있는 여러 객체를 구체적인 클래스에 의존하지 않고 만들 수 있게 해주는 것이 목적.
    • 즉, Product를 생산(Creator)하는 Factory 를 인터페이스로 묶어두어 → 클라이언트 쪽에서는 구체적인 클래스가 아닌 인터페이스에 의존하게 작성할 수 있습니다.

 

 

 

 

 

끝!

 

 

 

 

반응형