(인프런) 코딩으로 학습하는 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 를 인터페이스로 묶어두어 → 클라이언트 쪽에서는 구체적인 클래스가 아닌 인터페이스에 의존하게 작성할 수 있습니다.
끝!
'Java > Design Pattern' 카테고리의 다른 글
[디자인 패턴] 구조 패턴 - 어댑터 패턴 (Adapter Patterns) (0) | 2023.02.16 |
---|---|
[디자인 패턴] 생성패턴 - 프로토타입 패턴 (Prototype Patterns) (0) | 2023.02.15 |
[디자인 패턴] 생성패턴 - 빌더 패턴 (Builder Patterns) (0) | 2023.02.10 |
[디자인 패턴] 생성패턴 - 팩토리 메소드 패턴이란 (Factory Method patterns) (1) | 2023.02.08 |
[디자인 패턴] 생성패턴 - 싱글톤 패턴이란 (Singleton patterns) (0) | 2023.02.08 |