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
'Spring Series > Spring Framework' 카테고리의 다른 글
[Spring] 테스트 코드의 작성 (0) | 2022.03.10 |
---|---|
[Spring] @Value가 null을 가져오는 문제 (0) | 2022.03.06 |
[Spring] Spring Security(7) - 자동 로그인 기능 추가 (0) | 2021.02.09 |
[Spring] Spring Security(6) - 암호화로 보안 강도 높이기 (2) | 2021.02.08 |
[Spring] Spring Security(5) - 로그인 성공 커스터마이징 (0) | 2021.02.04 |
댓글