전공/Design Pattern

Design Pattern - Abstract Factory Pattern

ProgYun. 2023. 10. 7. 14:45

추상 팩토리 패턴의 핵심은 팩토리를 사용하는 클라이언트가 구체 클래스에 의존하지 않고, 추상화된 인터페이스에만 의존함으로써 클라이언트 코드의 변경 없이 용이하게 확장이 가능하도록 함에 있다.

즉 이 패턴을 사용함으로써 어떤 클래스의 구체 인스턴스에 접근하는지에 대해 클라이언트 코드는 몰라도 된다.

public class WhiteshipFactory extends DefaultShipFactory {  

    @Override  
    public Ship createShip() {  
        Ship ship = new Whiteship();  
        ship.setAnchor(new WhiteAnchor());  
        ship.setWheel(new WhiteWheel());  
        return ship;  
    }  
}

다음의 코드를 확인해보자

createShip()에서 new 연산자를 통해 WhiteAnchorWhiteWheel을 직접 생성하여 Ship 객체에 주입되는 것을 볼 수 있는데, 이렇게 되면 문제점이 WhiteShip을 생성할 때 다른 파츠를 이용하고 싶다면 WhiteShipFactory의 코드가 수정되어야 한다는 것이다(여기서 WhiteShipFactorynew 연산자를 이용하는 클라이언트 코드에 해당한다)

이 또한 OCP 원칙을 위배하는 것으로 볼 수 있고, 우리는 이전의 팩토리 메서드 패턴이 객체를 생성하는 과정을 추상화를 통해 Factory라는 인터페이스에 구체적인 객체 생성에 책임을 감싸고 구체 클래스에서 그 과정을 달리했듯이 추상화를 통해 Factory가 구체 클래스에 의존하지 않은 상태에서 다양한 파츠를 가진 인스턴스를 생성할 수 있도록 코드를 리팩터링 할 수 있다.

public class WhiteshipFactory extends DefaultShipFactory {  

    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;  
    }  
}

위 코드는 기존의 Factory 코드를 위의 목적에 맞게 리팩터링한 것이다.

다양한 WheelAnchor를 받아올 수 있도록 이 두 객체 또한 인터페이스화를 통해 추상화했다.

그리고 Factory 코드의 생성자 주입방식을 통해 어떤 ShipPartsFactory를 주입하느냐에 따라 생성하는 WhiteShip의 필드를 다르게 주입했다.

public class WhitePartsProFactory implements ShipPartsFactory {  
    @Override  
    public Anchor createAnchor() {  
        return new WhiteAnchorPro();  
    }  

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

다른 파츠를 넣고 싶은 경우 이제 우리는 ShipPartsFactory를 구현하는 클래스를 새로 생성하여 생성자 주입을 통해 할당해주기만 하면 내부 코드의 변경 없이도 유연하게 파츠의 확장이 가능해진다.

팩토리 메서드 패턴을 통해 확장이 필요한 경우 기존의 코드를 해결했어야 했던 단점이 해결되었고,
추상 팩토리 패턴을 통해 클라이언트 코드가 팩토리를 어떻게 사용할 것인가에 대한 내용이 구체 클래스를 언급하지 않아도 클라이언트 코드에서 생성자 주입을 통해 해결될 수 있도록 해결됐다.