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

 

 

 

*추상 팩토리 패턴

- 서로 관련있는 여러 객체를 만들어주는 인터페이스

  • 구체적으로 어떤 클래스의 인스턴스를(concrete product)를 사용하는지 감출 수 있다. (클라이언트에서 사용하는 인스턴스를 만들어 쓰는 코드를 인터페이스로 추상화한다)

- 구체적인 팩토리에서 구체적인 인스턴스를 만드는 부분은 팩토리 메소드 패턴과 비슷하지만 초점은 팩토리를 사용하는 클라이언트에 맞춰져 있다. 

 

 

 

 

- Product(Factory Method)

package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

import lombok.Getter;
import lombok.Setter;
import me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice.Oxidizer;
import me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice.Tonic;

@Getter @Setter
public class HairDye {
    ...
    
    private DarkOxidizer oxidizer;
    private DarkTonic tonic;

    ...
}

기존의 구현체에 필요한 데이터 필드를 추가한다.

 

 

- ConcreateProductA, ConcreateProductB

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public class DarkOxidizer{
}
package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public class DarkTonic{
}

추가된 구현체에 대한 클래스를 만든다.

 

 

- ConcreteCreator(Factory Method)

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

import me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice.DarkHairDye;
import me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice.DefaultHairDesigner;
import me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice.HairDye;

public class DarkHairDesigner extends DefaultHairDesigner {
    @Override
    public HairDye dyingService() {
        HairDye hairDye = new DarkHairDye();
        hairDye.setOxidizer(new DarkOxidizer());
        hairDye.setTonic(new DarkTonic());
        return hairDye;
    }
}

팩토리(creator)에 구현체에 추가된 Oxidizer나 Tonic를 구현하기 위해서 현재는 new 키워드를 통해 직접적으로 구현하는데, 추상 팩토리 패턴으로 클라이언트 측에서 사용하는 구현체에 따라 인스턴스가 정해지도록 한다.

 

 

- Abstract Factory

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public interface HairDyeProducts {

    Oxidizer useOxidizer();

    Tonic useTonic();
}

추상 팩토리 패턴으로 만들 인터페이스를 정의한다. 이 부분엔 추가되는 구현체(Product)를 정의한다.

 

 

- ProductA, ProductB

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public interface Oxidizer {
}
package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public interface Tonic {
}

추상 팩토리에서 사용될 구현체(Product)의 인터페이스를 정의한다.

 

 

- ConcreteProductA, ConcreteProductB

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public class DarkOxidizer implements Oxidizer{
}
package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public class DarkTonic implements Tonic{
}

인터페이스로 정의된 구현체를 구체적인 클래스를 정의한다.

 

 

- ConcreteFactory

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public class DarkHairDyeProducts implements HairDyeProducts{
    @Override
    public Oxidizer useOxidizer() {
        return new DarkOxidizer();
    }

    @Override
    public Tonic useTonic() {
        return new DarkTonic();
    }
}

추상 팩토리를 구현할 구현 클래스를 정의한다.

 

 

- ConcreteCreator(Factory Method)

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

import me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice.DarkHairDye;
import me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice.DefaultHairDesigner;
import me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice.HairDye;

public class DarkHairDesigner extends DefaultHairDesigner {

    private HairDyeProducts hairDyeProducts;

    public DarkHairDesigner(HairDyeProducts hairDyeProducts) {
        this.hairDyeProducts = hairDyeProducts;
    }

    @Override
    public HairDye dyingService() {
        HairDye hairDye = new DarkHairDye();
        hairDye.setOxidizer(hairDyeProducts.useOxidizer());
        hairDye.setTonic(hairDyeProducts.useTonic());
        return hairDye;
    }
}

기존 DarkHariDesigner에서 Oxidizer나 Tonic을 정의 하려면 new 인스턴스를 사용하기 때문에 의존성이 강하게 결합되어 있었지만, HairDyeProducts 인터페이스를 통해서 의존성의 결합을 느슨하게 변경했다.

 

 

추가적으로 형태는 같지만 다른 기능을 하는 클래스를 추가하는 경우,

 

- ConcreteProductC, - ConcreteProductD

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public class DarkExOxidizer implements Oxidizer{
}
package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public class DarkExTonic implements Tonic{
}

다른 구현체(Product)를 추가한다.

 

 

- ConcreteFactory

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

public class DarkHairDyeExProducts implements HairDyeProducts{
    @Override
    public Oxidizer useOxidizer() {
        return new DarkExOxidizer();
    }

    @Override
    public Tonic useTonic() {
        return new DarkExTonic();
    }
}

추상 팩토리를 구현하는 또 다른 구현체를 정의한다.

 

 

- Product(Factory Method)

package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

import lombok.Getter;
import lombok.Setter;
import me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice.Oxidizer;
import me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice.Tonic;

@Getter @Setter
public class HairDye {
    ...
    
    private Oxidizer oxidizer;
    private Tonic tonic;

    ...
}

기존에 DarkOxidizer, DarkTonic 등의 클래스 타입으로 되어있는 부분을 느슨한 결합을 위해 인터페이스 타입으로 수정한다.

 

 

- Client

package me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice;

import me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice.HairDesigner;
import me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice.HairDye;

public class Client {
    public static void main(String[] args) {
        HairDesigner hairDesigner = new DarkHairDesigner(new DarkHairDyeProducts());
        HairDesigner hairDesigner = new DarkHairDesigner(new DarkHairDyeExProducts());

        HairDye hairDye = hairDesigner.dyingService();
        System.out.println(hairDye.getOxidizer().getClass());
        System.out.println(hairDye.getTonic().getClass());
        
//      class me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice.DarkOxidizer
//      class me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice.DarkTonic

//      class me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice.DarkExOxidizer
//      class me.whiteship.designpatterns._01_creational_patterns._03_abstract_factory.practice.DarkExTonic        
    }
}

클라이언트에서 구조는 같지만 비슷한 형태의 인스턴스를 변경하기만 하면 다른 결과 값을 얻을 수 있다.

 

 

 

 

팩토리 메소드 패턴과 추상 팩토리 패턴은 비슷하다. 이 두가지는 관점의 차이이다. 팩토리 메소드 패턴은 객체 또는 인스턴스를 만드는(구현하는) 과정에 관점이 집중이 되어있고, 추상 팩토리 패턴은 팩토리를 사용하는 쪽(클라이언트)의 관점에 집중하여 보고있다.

  • 팩토리 메소드 패턴: 구체적인 객체 생성 과정을 하위 또는 구체적인 클래스로 옮기는게 목적
  • 추상 팩토리 패턴: 관련있는 여러 객체를 구체적인 클래스에 의존하지 않고 만들 수 있게 하는것이 목적

 

 

 

https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4

 

코딩으로 학습하는 GoF의 디자인 패턴 - 인프런 | 강의

디자인 패턴을 알고 있다면 스프링 뿐 아니라 여러 다양한 기술 및 프로그래밍 언어도 보다 쉽게 학습할 수 있습니다. 또한, 보다 유연하고 재사용성이 뛰어난 객체 지향 소프트웨어를 개발할

www.inflearn.com

+ Recent posts