본문 바로가기
  • 실행력이 모든걸 결정한다
Spring Series/Spring Framework

[Spring] 상속/인터페이스를 통한 확장

by 김코더 김주역 2022. 3. 4.
반응형

1. 상속을 통한 확장

1) Template method pattern

- Super class에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메소드나 protected 메소드 등으로 만들어 놓은 뒤에 sub class에서 오버라이딩해서 구현하는 패턴이다.

Template 메소드 : super class에서 기본적인 로직의 흐름 즉, 알고리즘 골격을 담은 메소드

- 변하지 않는 기능은 super class에 만들어두고 자주 변경되며 확장할 기능은 sub class에서 구현한다.

- Hook 메소드는 super class에서 기본적인 기능을 정의해두거나 비워뒀다가 서브클래스에서 선택적으로 오버라이드할 수 있도록 만들어둔 메소드이다.

 

 

2) Factory method pattern

- 구체적인 오브젝트 생성 방법을 sub class에서 결정하게 하는 패턴으로, Factory 메소드를 이용하여 구현부를 super class의 기본 코드로부터 독립시킬 수 있다.

 

보충) Factory 메소드란?

- 오브젝트 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메소드

- 팩토리 메소드는 주로 인터페이스 타입으로 오브젝트를 리턴하기 때문에, 오브젝트를 요청하는 클래스에서는 정확히 어떤 클래스의 오브젝트가 리턴될지 모른다.

- Factory 메소드를 이용하여 bean을 생성할 수도 있다. 그 방법으로는 스태틱 팩토리 메소드, 인스턴스 팩토리 메소드, @Bean 메소드가 있다. (더보기 참고)

더보기

스태틱 팩토리 메소드

- 클래스의 스태틱 메소드를 호출해서 인스턴스를 생성하는 방식

- 오브젝트 생성과 함께 초기화 작업이 필요한 경우에 사용되는 방식

- 예를 들어, 다음은 GlobalCounter 이라는 싱글톤 클래스의 createInstance 메소드를 호출하여 bean으로 등록해주는 설정이다.

<bean id="counter" class="GlobalCounter" factory-method="createInstance" />

 

인스턴스 팩토리 메소드

- 임의의 오브젝트의 메소드를 호출하여 bean을 생성하는 방식

<bean id="logFactory" class="a.b.c.LogFactory" />
<bean id="log" factory-method="createLog" factory-bean="logFactory" />

 

 

3) 예시

(1) 상속을 통한 확장 방법이 제공되는 UserDao

Super class

public abstract class UserDao {
    public void add(User user) throws ClassNotFoundException, SQLException {
        Connection c = getConnection();
        ...
    }

    public User get(String id) throws ClassNotFoundException, SQLException {
        Connection c = getConnection();
        ...
    }

    public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
}

 

Sub class

public class AUserDao extends UserDao {
    public Connection getConnection() throws ClassNotFoundException, SQLException {
        // 사용자 A의 Connection 오브젝트 생성 코드
    }
}

 

(2) Template 메소드 작성 예시

Super class

public abstract class Super {
    public void templateMethod() {
        // 기본 알고리즘 코드
        hookMethod();
        abstractMethod();
        ...
    }
    protected void hookMethod() {} // 선택적 오버라이딩 가능 (abstract X)
    public abstract void abstractMethod();
}

 

Sub class

public class Sub extends Super {
    protected void hookMethod() {
        ...
    }

    public void abstractMethod() {
        ...
    }
}

 

 

 

2. 인터페이스를 통한 확장

1) 인터페이스의 도입

- 인터페이스는 자바가 추상화를 위해 제공하는 가장 유용한 도구이다.

- 인터페이스를 통해 두 개의 클래스가 서로 긴밀하게 연결되어 있지 않도록 중간에 추상적인 느슨한 연결고리를 만들어줄 수 있다. 연결고리를 만든다는 것은 인터페이스를 구현한 나만의 클래스를 만드는 것이다.

- 결합력이 느슨해질수록 중복 코드가 줄어들기 때문에 수정에 대한 비용도 줄어든다.

- 클래스 상속 방식과 다르게 인터페이스는 다중 상속이 가능하기 때문에 더 유연한 설계가 가능하다.

- 인터페이스를 통해 필요한 메소드만 노출시켜서 불필요한 결합도를 낮출 수 있다.

 

 

2) 예시

인터페이스

public interface ConnectionMaker {
	public Connection makeConnection() throws ClassNotFoundException, SQLException;
}

 

인터페이스의 구현체

public class DConnectionMaker implements ConnectionMaker {
    ...
    public Connection makeConnection() throws ClassNotFoundException, SQLException {
    	// 구현
    }
}

 

UserDao

public class UserDao {
    private ConnectionMaker connectionMaker;
    
    // 생성자의 파라미터를 통해 ConnectionMaker의 구현체인 DConnectionMaker을 받는다.
    public UserDao(ConnectionMaker connectionMaker) {
    	this.connectionMaker = connectionMaker;
    }
    
    public void add(User user) throws ClassNotFoundException, SQLException {
        Connection c = connectionMaker.makeConnection();
        ...
    }
    
    public User get(String id) throws ClassNotFoundException, SQLException {
    	Connection c = connectionMaker.makeConnection();
        ...
    }
}

 

 

 

● 참고 자료 : 토비의 스프링 3.1

 

 

반응형

댓글