Design Pattern

Factory Method

Jungsoomin :) 2020. 11. 24. 21:24

템플릿 메서드를 사용하는 생성 메서드 패턴

 

모든 디자인 패턴의 목표는 구조와 구현의 분리에 있다.

 

  • 객체 생성이 클래스 자신을 뜻하지 않아도 된다.
  • 메서드 오버로딩 시 리턴타입은 영향을 주지 않는데, 팩토리메서드는 리턴 값이 다른 생성 메서드를 가질 수 있다.
  • 내부에서 생성 과정이 여러가지 일 경우 Template Method 와 함께 사용될 수 있다.

  1. 객체를 만드는 추상클래스(Template Method, Factory Method) + 만들 객체의 인터페이스로 골격을 갖춘다.
  2. 추상클래스의 상속 클래스에서 만들 객체의 인터페이스의 구현체를 만들어내는 틀을 가진다.

만들 객체를 추상화한 인터페이스 와 만들어낼 Factory 를 추상화한 추상클래스

Product 인터페이스 / 구현 클래스

public interface Product {
    void use();
}

class CorporationCard implements Product {

    private String owner;

    CorporationCard(String owner) {
        this.owner = owner;
    }

    @Override
    public void use() {
        System.out.printf("%s 의 카드를 사용합니다.",owner);
    }
}

class IDCard implements Product {

    private String owner;

    IDCard(String owner) {
        this.owner = owner;
    }

    @Override
    public void use() {
        System.out.printf("%s 의 카드를 사용합니다.%n",owner);
    }
}

Factory 추상클래스 ( 템플릿 메서드 패턴을 따르고 있다.) / Product 구현체에 맞는 Factory

public abstract class Factory {
    //템플릿 메서드
    protected abstract Product createProduct(String owner);

    protected abstract void loggingProduct(Product product);

    //팩토리 메소드
    public final Product created(String owner){
       Product product = createProduct(owner);
       loggingProduct(product);
       return product;
    }

}

public class CorporationCardFactory extends Factory {
    @Override
    protected Product createProduct(String owner) {
        return new CorporationCard(owner);
    }

    @Override
    protected void loggingProduct(Product product) {
        System.out.printf("사용 중인 Product 클래스 : %s %n" , product.getClass());
    }
}

public class IDCardFactory extends Factory {

    @Override
    protected Product createProduct(String owner) {
        return new IDCard(owner);
    }

    @Override
    protected void loggingProduct(Product product) {
        System.out.printf("사용 중인 Product 클래스 : %s %n" , product.getClass());
    }

}

메인 메서드 호출

public class Main {
    public static void main(String[] args) {
        Factory idCardFactory  = new IDCardFactory();
        Product soominCard = idCardFactory.created("Soomin");
        soominCard.use();

        Factory corporationCardFactory = new CorporationCardFactory();
        Product copCard = corporationCardFactory.created("cop");
        copCard.use();

    }
}
// 로그
사용 중인 Product 클래스 : class Factory.IDCard 
Soomin 의 카드를 사용합니다.
사용 중인 Product 클래스 : class Factory.CorporationCard 
cop 의 카드를 사용합니다.

객체를 만들어내는 부분Sub-Class에 위임하는 것이다.


하나의 팩토리 메서드를 가지고 다양한 구현체를 찍어내는 방법

DriverManager.getConnection() 메서드가 이런 형태를 띈다고 생각해 왔다. 하나의 팩토리 메서드 라고 보았다.

 

Factory, 공장 그대로 다양한 객체를 하나의 메서드에서 찍어내는 것을 보여준다.

Robot 과 리턴시킬 구현체들

public interface Robot {
    void printName();
}

public class DefaultRobot implements Robot {

    private final static String MODEL = "Default Version";

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void printName() {
        System.out.printf("해당 로봇 모델은 %s 입니다. 기종 이름은 %s 입니다. %n",MODEL,name);
    }
}

public class ModifiedRobot implements Robot {

    private final static String MODEL = "Modified Version";

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void printName() {
        System.out.printf("해당 로봇 모델은 %s 입니다. 기종 이름은 %s 입니다. %n",MODEL,name);
    }
}

ClassName , Keyword 로 원하는 객체를 만들어내는 Factory

public abstract class RobotFactory {
    public abstract Robot createModel(String str,String name);
}

public class ClassNameRobotFactory extends RobotFactory {
    @Override
    public Robot createModel(String className,String name) {
        try{
            Class<?> clazz = Class.forName(className);
            Robot obj = (Robot)clazz.newInstance();
            if(obj instanceof DefaultRobot){
                DefaultRobot defaultRobot = (DefaultRobot)obj;
                defaultRobot.setName(name);
                return defaultRobot;
            }
            ModifiedRobot modifiedRobot = (ModifiedRobot)obj;
            modifiedRobot.setName(name);
            return modifiedRobot;
        }catch(Exception e){
            e.printStackTrace();
            return null;
        }
    }
}

public class KeywordRobotFactory extends RobotFactory {
    @Override
    public Robot createModel(String keyword,String name) {
        switch (keyword){
            case "default":
                DefaultRobot defaultRobot = new DefaultRobot();
                defaultRobot.setName(name);
                return defaultRobot;
            case "modified":
                ModifiedRobot modifiedRobot = new ModifiedRobot();
                modifiedRobot.setName(name);
                return modifiedRobot;
            default:
                return null;
        }
    }
}

호출하는 메인메서드와 로깅

public class Main {
    public static void main(String[] args) {
        RobotFactory classNameRobotFactory = new ClassNameRobotFactory();
        Robot deedea = classNameRobotFactory.createModel("Factory.HeadFirst.DefaultRobot","deedea");
        Robot tom = classNameRobotFactory.createModel("Factory.HeadFirst.ModifiedRobot", "tom");

        deedea.printName();
        tom.printName();

        System.out.println("===========================================================");

        RobotFactory keywordRobotFactory = new KeywordRobotFactory();
        Robot defaultModel = keywordRobotFactory.createModel("default", "deedea");
        Robot modifiedModel = keywordRobotFactory.createModel("modified", "tom");

        defaultModel.printName();
        modifiedModel.printName();
    }
}

////로깅
해당 로봇 모델은 Default Version 입니다. 기종 이름은 deedea 입니다. 
해당 로봇 모델은 Modified Version 입니다. 기종 이름은 tom 입니다. 
===========================================================
해당 로봇 모델은 Default Version 입니다. 기종 이름은 deedea 입니다. 
해당 로봇 모델은 Modified Version 입니다. 기종 이름은 tom 입니다. 

'Design Pattern' 카테고리의 다른 글

Prototype  (0) 2020.11.29
SingleTon Pattern  (0) 2020.11.24
Template Method  (0) 2020.11.23
Adapter  (0) 2020.11.23
Strategy  (0) 2020.11.23