JAVA를 공부를 하다보면, `다형성`과 `코드 재사용` 에 대해서 중요한 개념을 알게 됩니다. 이와 관련하여 우선, 추상클래스와 인터페이스를 다뤄보려고 합니다.
추상클래스란 무엇인가?
추상 메소드(abstract method)란 자식 클래스에서 반드시 오버라이딩해야만 사용할 수 있는 메소드를 의미합니다. 이러한 메소드를 포함한 클래스를 추상 클래스 라 합니다. 자바에서 추상 클래스와 추상 메소드를 선언하여 사용하는 목적은 추상 클래스를 상속받는 자식 클래스가 반드시 추상 메소드를 구현하도록 하기 위함입니다.
이를 공부하기 위한 대표적인 예시로 Unit이라는 추상클래스를 만들고 움직임(move,stop)을 표현합니다.
abstract class Unit {
int x, y;
abstract void move(int x, int y); // 지정된 위치로 이동
void stop() {} // 현재 위치에 정지
}
추상 클래스를 상속 받아서 각각 객체는 같은 움직임에 대해서 다른 동작을 구현 합니다. 하지만, stop은 누구나 똑같은 기능을 진행합니다. Unit 추상클래스에 move는 abstract로 선언되어 있어 강제성이 부여되고, move를 꼭 부여 해야 합니다.
class Marine extends Unit{
void move(int x, int y) {
System.out.println("걸어서 이동");
}
void stimPack() {} // 고유 능력 스팀팩 사용
}
class Tank extends Unit{
void move(int x, int y) {
System.out.println("굴러서 이동");
}
void siegeMode() {} // 고유 능력 시즈 모드 사용
}
인터페이스란 무엇인가?
인터페이스는 기본적으로 무엇을 할 수 있는지(What to do) 에 대한 명세(Specification) 또는 계약(Contract)을 정의하는 것입니다. 사용자가 기기를 쉽게 동작시키는데 도움을 주는 상호작용 시스템을 의미한다.
추상 클래스와 사실 비슷한 성질을 가지고 있긴 하지만, 인터페이스는 추상클래스와 다른점이 있습니다.
- 클래스와 달리 인터페이스의 모든 필드는 public static final로 선언되며 생략이 가능합니다. 즉 모든 필드는 상수이다.
Java 8 이전에는 인터페이스에서 일반 메서드(즉, 구현이 있는 메서드)를 사용할 수 없었습니다. 인터페이스는 오로지 추상 메서드만을 정의할 수 있었고, 이는 인터페이스가 계약을 정의하는 "약속" 역할을 하도록 설계되었기 때문입니다.
서비스 계층에서 제공해야 하는 행위(기능)들을 인터페이스로 정의하고, 해당 인터페이스를 실제 서비스 구현 클래스에서 구현하는 것은 객체 지향 설계에서 매우 권장되는 좋은 패턴입니다. 주로 서비스 인터페이스와 , 레파지토리 인터페이스로 사용됩니다.
관심사의 분리 (Separation of Concerns):
- 서비스 계층: 비즈니스 규칙, 트랜잭션 관리 등 핵심 로직에 집중합니다. "데이터를 어떻게 가져오는지"는 신경 쓰지 않고, "가져온 데이터로 무엇을 할지"에 집중합니다.
- 레포지토리 계층: 데이터베이스와의 통신, 데이터 CRUD 작업에 집중합니다. "이 데이터가 어떤 비즈니스 로직에 쓰이는지"는 신경 쓰지 않고, "어떻게 데이터를 효율적으로 저장하고 조회할지"에 집중합니다
실제 서비스 계층에서 레포지토리 계층에서 구현한 것을 주입하여 사용합니다.
AgentRepository(데이터 접근과 관련된 인터페이스) --> AgentImplement(실제 구현) ,
ActionService( 일반 인터페이스) --> ActionServiceImpl(실제 구현)
ActionServiceImpl은 비즈니스 로직에 집중하고, 데이터 접근은 AgentRepository에 위임하기 위함입니다.
// 1. 레포지토리 인터페이스
public interface AgentRepository { // BaseAbstractDao 상속은 일단 생략 (핵심 설명에 집중)
List<AgentVO> selectAgentList(AgentVO agent);
}
// 2. 레포지토리 구현 클래스
// @Repository // 실제로는 스프링 빈으로 등록되어야 함
public class AgentImplement implements AgentRepository {
@Override
public List<AgentVO> selectAgentList(AgentVO agent) { // AgentRepository와 시그니처 일치!
System.out.println("AgentImplement: selectAgentList 호출됨");
// 여기에 실제 DB에서 Agent 목록을 가져오는 로직 구현
// 예: return jdbcTemplate.query(...); 또는 myBatisMapper.selectAgentList(agent);
return new ArrayList<>(); // 임시 반환
}
}
// 3. 서비스 인터페이스
public interface ActionService {
List<ActionVO> selectActionList(ActionVO action); // ActionVO를 사용하는 서비스 메소드
// 만약 Agent 정보를 사용하는 서비스도 있다면 여기에 추가 가능
// List<AgentVO> getAgentListForSomeAction(SomeCriteria criteria);
}
// 4. 서비스 구현 클래스
// @Service // 실제로는 스프링 빈으로 등록되어야 함
public class ActionServiceImpl implements ActionService {
// ActionService가 Agent 정보를 가져오기 위해 AgentRepository를 사용할 수 있음
private final AgentRepository agentRepository;
// 생성자 주입 (스프링 환경에서는 @Autowired 자동 처리)
public ActionServiceImpl(AgentRepository agentRepository) {
this.agentRepository = agentRepository;
}
@Override
public List<ActionVO> selectActionList(ActionVO action) {
System.out.println("ActionServiceImpl: selectActionList 호출됨");
// 여기에 비즈니스 로직 구현
// 필요하다면 agentRepository를 사용하여 Agent 정보를 가져올 수 있음
// 예: AgentVO agentFilter = new AgentVO();
// List<AgentVO> agents = agentRepository.selectAgentList(agentFilter);
// // agents 정보를 활용하여 ActionVO 목록 생성 또는 다른 작업 수행
return new ArrayList<>(); // 임시 반환
}
// 만약 ActionService 내에서 직접 Agent 목록을 반환하는 서비스가 필요하다면:
/*
public List<AgentVO> getAgentListForSomeAction(SomeCriteria criteria) {
AgentVO agentFilter = new AgentVO();
// criteria 정보를 agentFilter에 맞게 설정
return agentRepository.selectAgentList(agentFilter);
}
*/
}
캡슐화란 무엇인가?
데이터와, 데이터를 처리하는 행위 이 두가지를 묶어서 사용하고, 그 행위를 보여주지 않는 개념 입니다.
일반적으로 getter/setter 를 통해서 데이터를 다루는 기술에 사용 됩니다.
아래는 getPrice()를 캡슐화 한 내용입니다.
class goods {
private int number;
public goods(int number) {
this.number = number;
}
public double getPrice() {
return number * 0.9;
}
}
실제로 getPrice()를 사용할때는 0.9를 곱하는 행위를 숨기고 값을 불러내 사용하는것 입니다.
public void foo(Goods goods) {
double discountedPrice = goods.getPrice();
}
'개발일지 > JAVA,SPRING' 카테고리의 다른 글
| 📌 Java 접근 제어자(private / default / protected / public) 완전 정리 (0) | 2025.12.12 |
|---|---|
| @Bean 객체 만들기, @Component vs @Configuration (4) | 2025.05.23 |
| JAVA, JDK 에 대한 진실. (1) | 2025.05.20 |
| 쿠키,세션 알아보기 (With Spring) (2) | 2025.05.19 |