본문 바로가기

Develop/Design Pattern

[Design Pattern] 팩토리 메소드 (Factory Method) 패턴

728x90

해당 포스팅은 [Design Pattern] 팩토리 (Factory) 패턴 의 하위 문서입니다.



1. 개요

팩토리 메소드 디자인 패턴 (Factory Method Design Pattern) (이하 팩토리 메소드)객체 생성(Creation)과 책임(Responsibility)을 공장(Factory) 의 하위 클래스에 위임(Delegate)하여 하위 클래스에서 어떤 클래스의 인스턴스를 생성할지 결정하도록 하는 패턴이다.

팩토리 메소드는 주로 단일 제품에 대한 생성을 다루고, 하위 클래스에서 해당 메소드를 구현함으로써 특정 클래스의 한다.

2. 상황

  • 객체 생성이 복잡하거나 변경되기 쉬울 때
  • 객체 생성 코드가 중복될 때

3. 다이어그램

3.1. 설명

  • Factory 가 추상 클래스로 존재한다.
  • Product 의 하위 구체 클래스들에 대응되는 Factory 구체 클래스들이 존재한다.
  • Product 객체를 생성하는 코드는 Factory 구체 클래스의 create() 에 구현되어 있다.

4. 구현

public interface Product {}

class ProductA implements Product {}
class ProductB implements Product {}
public abstract class Factory {
  public abstract Product create();
}

class FactoryA extends Factory {
  @Override
  public Product create() { return new ProductA(); }
}

class FactoryB extends Factory {
  @Override
  public Product create() { return new ProductB(); }
}
class Client {
  public static void main(String[] args) {
    Product productA = new FactoryA().create();
    Product productB = new FactoryB().create();
  }
}

5. 예시

import java.lang.Math;

public abstract class Shape {
  protected double x;
  protected double y;

  public abstract double getArea();

  @Override
  public String toString() {
    return String.format("Position: (%.1f, %.1f)\nArea: %.2f", x, y, getArea());
  }
}

class Rectangle extends Shape {
  private double width;
  private double height;

  Rectangle(double x, double y, double width, double height) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
  }

  public double getArea() { return width * height; }

  @Override
  public String toString() {
    return "\n[Rectangle]\n" 
      + super.toString() 
      + String.format("\nWidth: %.1f, Height: %.1f", width, height);
  }
}

class Circle extends Shape {
  private double radius;

  public Circle(double x, double y, double radius) { 
    this.x = x;
    this.y = y;
    this.radius = radius; 
  }

  public double getArea() { return Math.PI * Math.pow(radius, 2); }

  @Override
  public String toString() {
    return "\n[Circle]\n"
      + super.toString() 
      + String.format("\nRadius: %.1f", radius);
  }
}
public abstract class ShapeFactory {
  public abstract Shape create(double x, double y, double w, double h);
  public abstract Shape create(double x, double y, double r);
}

class RectangleFactory extends ShapeFactory {
  @Override
  public Shape create(double x, double y, double w, double h) { 
    return new Rectangle(x, y, w, h); 
  }

  @Override
  public Shape create(double x, double y, double r) {
    throw new UnsupportedOperationException("Method unimplemented error");
  }
}

class CircleFactory extends ShapeFactory {
  @Override
  public Shape create(double x, double y, double r) {
    return new Circle(x, y, r);
  }

  @Override
  public Shape create(double x, double y, double w, double h) {
    throw new UnsupportedOperationException("Method unimplemented error");
  }
}
public class Client {
  public static void main(String[] args) {
    Shape rectangle = new RectangleFactory()
        .create(50.0, 40.0, 20.0, 30.0);
    Shape circle = new CircleFactory()
        .create(30.0, 20.0, 10.0);

    System.out.println(rectangle);
    System.out.println(circle);
  }
}

실행결과


[Rectangle]
Position: (50.0, 40.0)
Area: 600.00
Width: 20.0, Height: 30.0

[Circle]
Position: (30.0, 20.0)
Area: 314.16
Radius: 10.0

6. 장단점

6.1. 장점

  • 코드 중복 최소화
  • 유연성, 확장성 증가
  • Client 코드 간소화

6.2. 단점

  • 새로운 객체를 추가 시 하위 클래스 생성 필요
  • 코드 복잡성 증가

관련 포스팅

728x90