SSAFY11th-book-study / book-study

SSAFY 11기 6반의 '토비의 스프링 스터디'
0 stars 0 forks source link

[1.2.3] 탬플릿 메소드 패턴 #4

Closed a-young-kim closed 8 months ago

a-young-kim commented 9 months ago
public class NUserDao extends UserDao{
    public Connection getConnection(){
    // N사 DB 생성 코드 
    }
}

해당 클래스는 탬플릿 메소드 패턴을 사용한 클래스인지 궁금합니다. 만약에 맞다면 해당 클래스는 팩토리 메소드 패턴을 사용하였는데 팩토리 메소드 패턴을 사용한 경우에는 무조건 탬플릿 메소드 패턴을 사용한 것인지도 궁금합니다.

limjongheok commented 9 months ago

제 개인적인 생각으로는 우선 템플릿 메소드 패턴은 상위 클래스 add() 와 get() 처럼 골격을 정의하고 서브클래스에서 해당 골격 안 일부를 구현 혹은 정의하는 방식이고 팩토리 메소드 패턴은 인스턴스를 생성하는 것을 분리 하여 생성 클래스에 위임하는 것 이라고 알고있어 우선 두 패턴의 목적이 다르다고 생각하며 현재 방식은 추상팩토리 방식을 이용해서 그렇지

현재 추상팩토리방식

public abstract class UserDao {
    public void add(User1 user1) throws  ClassNotFoundException, SQLException{ // 템플릿 메소드 패턴
        Connection c = getConnection();

        PreparedStatement ps = c.prepareStatement("insert into users(id,name,password) values(?,?,?)");
        ps.setString(1,user1.getId());
        ps.setString(2,user1.getName());
        ps.setString(1,user1.getPassWord());

        ps.executeUpdate();
        ps.close();
        c.close();
    }
 public  abstract  Connection getConnection() throws SQLException; // 추상팩토리 패턴

팩토리 클래스 분리 방식

public class UserDao {
    private UserDaoFactory userDaoFactory;

    public UserDao(UserDaoFactory daoFactory){
        this.userDaoFactory = daoFactory;
    }
    public void add(User1 user1) throws  ClassNotFoundException, SQLException{ // 템플릿 메소드 패턴
        Connection c = userDaoFactory.getConnection();

        PreparedStatement ps = c.prepareStatement("insert into users(id,name,password) values(?,?,?)");
        ps.setString(1,user1.getId());
        ps.setString(2,user1.getName());
        ps.setString(1,user1.getPassWord());

        ps.executeUpdate();
        ps.close();
        c.close();
    }

class UserDaoFactory {
     public Connection getConnection(){
     return Connection;
    }
}

다음과 같이 Factory 클래스를 따로 분리하여 UserDao에서 생성자주입으로 받는 형식의 팩토리 메소드면 템플릿 메소드 패턴과 관련이 없지 않을까 생각합니다.

a-young-kim commented 9 months ago

팩토리 메소드 패턴의 정의 자체가 서브클래스에서 오브젝트 생성을 정하는 패턴으로 알고 있는데 두번째 코드는 상속이 되어 있지 않기 때문에 팩토리 메서드 패턴이라고 할 수 없지 않을까요?

sootudio commented 9 months ago

질문에 올라온 클래스는 템플릿 메소드 패턴을 사용했다고도, 팩토리 메소드 패턴을 사용했다고도 볼 수 있을것 같습니다.

우선, 상위 클래스인 UserDao에서 add()나 get() 등 알고리즘의 기본적인 단계를 정의하고, 알고리즘의 일부 단계인 getConnection() 메서드를 서브 클래스인 NUserDao에서 구현하기 때문에 템플릿 메소드 패턴의 조건에 부합합니다.

그리고, 상위 클래스인 UserDao에서 DB 연결 객체를 생성하기 위한 getConnection() 메소드를 정의했고, 해당 객체의 생성을 서브 클래스인 NUserDao에 위임했기 때문에 팩토리 메소드 패턴의 조건에도 부합합니다.

저도 두 가지가 헷갈려서 계속 찾아보고 있긴 한데... 어떤 코드가 템플릿 메소드 패턴이고, 팩토리 메소드 패턴인지 명확하게 구분하는 것은 조금 모호한것 같습니다. 실제로도 두 가지를 혼합해 쓰는 경우가 종종 있다고 합니다. (명확한 기준도 있긴 합니다... 예를 들어, 서브 클래스에 객체를 생성하는 부분이 없다면 팩토리 메소드 패턴이라고 볼 수는 없습니다.)

하지만 질문에 올리셨던 "팩토리 메소드 패턴을 사용한 경우에는 무조건 탬플릿 메소드 패턴을 사용한 것인지" 에 대해서는 아니라고 생각합니다. 예를 들어,

public abstract class VehicleFactory {
    // 팩토리 메소드: 서브클래스에서 구체적인 차량 객체를 생성
    public abstract Vehicle createVehicle();

    public void displayVehicle() {
        Vehicle vehicle = createVehicle();
        System.out.println("Created a " + vehicle.getType());
    }
}

public class CarFactory extends VehicleFactory {
    @Override
    public Vehicle createVehicle() {
        // Car 객체 생성
        return new Car();
    }
}

(코드는 지피티가 만들어 줬습니다...ㅎㅎ 직접 만들었다가 적절하지 않은 예시를 만들까봐,,,)

해당 경우에 상위 클래스인 VehicleFactory에서 서브 클래스인 CarFactory에 Car 객체의 생성을 위임하고 있지만(팩토리 메소드 패턴 사용), 상위 클래스에서 프로그램의 동작 알고리즘의 기본 틀을 정의하고 그 일부를 서브 클래스에서 구현한다고 보기는 어렵기 때문에 템플릿 메소드 패턴을 사용한다고 보기는 어려울 것 같습니다. 상위 클래스에 createVehicle을 호출하여 결과를 출력하는 displayVehicle 메소드가 있긴 하지만, 해당 메소드는 알고리즘의 일부분이라기보다는 단순히 객체 생성 결과를 활용하는 기능입니다.

사실 제가 설명해 놓고도 명확한 기준이 없어서(displayVehicle이 알고리즘의 일부분이라고 생각하는 사람이 있다면...?) 다양한 코드에 일반화 시키기가 어려울 것 같긴 한데... 결국 팩토리 메소드 패턴을 적용했다고 해서 무조건 템플릿 메소드 패턴은 아니며, 해당 코드(상위클래스, 서브클래스)가 어떤 목적으로 만들어졌는지 확인해보면 각자의 기준에 따라 모호한 부분은 있겠지만, 위의 예시 말고도 다른 반례들도 만들 수 있을 것 같습니다.

limjongheok commented 9 months ago

찾아보니 제가 구현한 것은 팩토리 메소드 패턴이라 할수 없다하네요 팩토리 메소드 패턴의 정의가 팩토리 메소드 패턴을 이용하면 클래스의 인스턴스를 만드는 일을 서브클래스에게 맡기는 것 라합니다 https://velog.io/@ljo_0920/%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C 관련 내용입니다.

limjongheok commented 9 months ago

그렇다면 궁금한게 만약

public interface Factory{
     Connection getConnection();

}

class UserDaoFactory implements Factory {
     @Override
     public Connection getConnection(){
     return Connection;
    }
}

public class UserDao {
    private Factory userDaoFactory;

    public UserDao(Factory daoFactory){
        this.userDaoFactory = daoFactory;
    }
    public void add(User1 user1) throws  ClassNotFoundException, SQLException{ // 템플릿 메소드 패턴
        Connection c = userDaoFactory.getConnection();

        PreparedStatement ps = c.prepareStatement("insert into users(id,name,password) values(?,?,?)");
        ps.setString(1,user1.getId());
        ps.setString(2,user1.getName());
        ps.setString(1,user1.getPassWord());

        ps.executeUpdate();
        ps.close();
        c.close();
    }

다음과 같이 인터페이스를 활용하여 factory 구현시 서브 클래스에서 인스턴스를 생성하니 팩토리 메서드 패턴이라 볼수 있는데 혹시 서브 클래스가 자신의 서브 클래스로 이해해야 하나요??