지난 글에서는 객체지향에 대해 간단하게 알아보았다.
이번에는 TDA원칙을 통해 객체가 어떻게 능동적으로 동작하도록 하는지 학습하려고 한다.
만화나 그런걸 보면 꼭 악당이 지면 뒤에 더 강한 악당들이 이런말을 한다.
크크큭...! 그 녀석은 우리중에 최약체였지...! 하면서 친절하게 주인공이 최강이 될 때까지 맞춤으로 싸워주는 악당들...
그렇다... 사실 이전 글도 마찬가지로 흔히 이야기하는 가장 약한 녀석이었다.
1. 덕 타이핑과 TDA
이전 글에서는 그냥 객체지향 식으로 하면 된다~ 이런 식으로 햇지만
이번에는 좀 더 행동을 어떻게 하냐에 따라서, 객체지향 개발을 쉽게 할 수 있도록
덕 타이핑과 TDA에 대해 먼저 알아보려고 한다.
덕 타이핑(duck typing)은 동적 타이핑의 한 종류로, 객체의 변수 및 메소드의 집합이 객체의 타입을 결정하는 것을 말한다.
- 위키백과 : 덕 타이핑
'If it walks like a duck and it quacks like a duck, then it must be a duck'
해석해보면 '오리처럼 걷고, 오리처럼 꽥꽥거리면, 그것은 틀림없이 오리다.' 라는 뜻이다.
행위가 동일하면, 같은 클래스로 본다는 말이다.
Tell-Don't-Ask는 사람들이 객체지향이 데이터를 그 데이터에 대해 작동하는 함수들과 함께 묶는 것임을 기억하는 데 도움이 되는 원칙이다.
Tell-Don't-Ask is a principle that helps people remember that object-orientation is about bundling data with the functions that operate on that data.
마틴파울러씨의 사이트에 Tell Dont Ask 에 대해 설명하고 있다.
우리가 객체에게 데이터에 따라서 행동을 요청하기보다는 객체에게 뭘 하길 말해야만 한다.
이는 객체가 데이터에 따라 어떤 동작을 하도록 유도한다.
2. 행동과 구현
자! 그럼 어떻게 이걸 실제 객체지향에 설계하면 어떻게 할까?
다음 예시를 통해서 보도록 하자.
키메라에게 주어진 과제.
최근에 한강버스를 운영한다고 하는데, 그래! 한강버스... 배 클래스를 만들어 본다면?
우선 두 가지의 버전이 있다.
배에 필요한 부품과 운전시 필요한 속성을 떠올렸다.
Ship.java - 데이터 위주 사고
public class Ship {
private String modelName;
private Engine engine;
private float speed;
private float direction;
private long coverablePeople;
}
이번에는 배가 어떻게 행동해야 하는지 떠올려서 개발을 한다면...?
다음과 같은 결과를 만들 수 있다.
Ship.java - 행동 위주 사고
public class Ship {
public void drive() {}
public void changeDirection(float amount) {}
public void speedUp(float amount) {}
public void slowDown(float amount) {}
}
이렇게 데이터 위주의 사고와 행동 위주의 사고를 기반으로 한 경우 각각 결과가 다르다.
데이터 위주의 경우, 전에 이야기한 TDA를 어떻게 할 것인지 전혀 모르겟다.
그에 반면에 행동 위주 사고로 클래스를 작성한 경우 좀 더 객체지향적인 코드가 나온다.
객체지향적인 코드를 작성하기 위해서는 행동에 집중해서, 행동이 객체를 결정하도록 해야 한다.
???
public class ??? {
public void eat() {}
public void earn() {}
public void read() {}
public void exercise() {}
public void work() {}
}
이렇게 행위들만 보면 이게 뭘까 싶다. 이름을 지어볼까?
먹고, 벌고, 읽고, 운동하고 그리고 일하고...
필자는 동물? 그거보다는 읽고 번다는 것에서 사람이라고 할 것 같다.
이렇듯이 행동을 보면 객체를 정의하는것이 한결 쉽다. 나중에 객체에게 무슨 일을 일임해야 하나 고민하는 것을 행동 중심으로
설계를 하면서 해결해주는 것이다.
3. 더 나아가기
그런데 이전에 만든 Ship.java 에 메소드의 구현이 없으니 한번 해보도록 하겠다.
메서드 구현
public class Ship {
private float speed;
public void drive() {}
public void changeDirection(float amount) {}
public void speedUp(float amount) {
speed += amount;
if(speed > 200) speed = 200f;
}
public void slowDown(float amount) {
speed -= amount;
if(speed < 0) speed = 0f;
}
}
어라라... Ship 클래스에 속성이 생겼다.
메서드를 구현하려고 하니 데이터 위주 사고로 돌아간거 아닌가?
하지만 우리는 이미 Java에서 제공하는, 행동을 표현하는데 좋은 문법을 알고있다.
ShipInterface.java
public interface ShipInterface {
void drive();
void changeDirection(float amount);
void speedUp(float amount);
void slowDown(float amount);
}
필자는 해당 부분을 보면서 참 재미있었는데, 초기 설계 단계에서 상세 구현을 안하면 너무 무책임하지 않은가?
하는 고민을 하는데, 이는 오히려 잘된것이다. 각자 개개인이 맡은 업무를 잘 해내리라 믿는거란다.
여기서 Interface의 정의에 대해 자바 공식문서에서 보도록 하자.
인터페이스란 무엇인가?
이미 알다시피, 객체는 그들이 노출하는 메소드들을 통해 바깥 세상과 그들의 상호작용을 정의한다.
메소드는 바깥 세상에서 객체의 인터페이스를 형성한다.
예를 들어, 텔레비전위에 버튼들이 당신과 플라스틱 케이스의 다른 쪽을 연결하는 인터페이스인 것이다.
당신이 power 버튼을 누르면 티비가 켜지고 꺼진다.
가장 흔한 형식으로, 인터페이스는 빈 body를 가진 메소드와 연관된 하나의 그룹이다.
...
코드 설명...
...
인터페이스를 구현하면 클래스는 그것이 제공한다고 약속한 행위에 대해 더 정형화하도록 돕는다.
인터페이스는 클라스와 바깥 세계 사이의 계약을 형성하고 이 계약은 컴파일러에 의해 빌드할 때 강제된다.
인터페이스를 통해 구현이 없이 메소드를 정의할 수 있으며 객체와 바깥 세상간에 어떻게 메시지를 주고받는지에만 집중해서 작업하도록 함으로 상세한 코드를 신경쓰지 않고 작업을 할 수 있게 해준다.
공식 문서에서 계약을 만든다고 한다. 그렇다. 인터페이스를 잘 만들어야 좋은 계약을 하는 것이다. (집문서 가져와!)
글을 읽어보면 약속한 행위에 대해 더 정형화하도록 돕는다는데, 명확하게 말하면 행동들의 집합이지 이것이 행동은 아닌 것이다.
이렇다 보면 interface에 private 이 없는 이유가 자연스럽게 나온다.
아니... 외부 세계와의 계약을 형성해서 메시지를 주고받아야 하는데... private이라고? 애초에 그러면 존재 의의를 벗어나는 행위로 간주한다. (private 코드 작성 불가)
애초에 public 도 작성을 하면 blur 처리가 된다.
그치. 애초에 interface 존재 의의 자체가 메시지 주고받는건데... 당연이 public 이지
4. 확장하기
우리가 역할에 집중을 하면 유연한 설계를 얻을 수 있다고 한다.
사실 위에서 만든 ShipInterface는 뭔가... 배에게만 국한되는것이라기 보다는...
좀 더 일반적인 단어로 표현할 수 있다.
아무래도 탈 것 이 어울린다.
public interface Vehicle {
public void drive();
void changeDirection(float amount);
void speedUp(float amount);
void slowDown(float amount);
}
이렇게 되면 언젠가 다양한 탈것을 만드는데 크게 문제가 없다.
Vehicle 인터페이스는 은 이제 변경에는 닫혀있고, 확장에는 열려있다.
어디서 많이 들어보지 않았나? SOLID 중에 Open-Closed Principle이다.
그러면 이제 뭔가... SOILD한 코드를 작성할 수 있을거 같은데?
다음 글에서는 객체지향 설계를 SOLID를 통해 알아보면서 학습할 것이다.
다시 책을 읽으며 복습하니 정말 재미있고, 어서 하고 다른거 공부하고싶다...
최근에 Netty 관련해서 정보도 정리해놧는데, 이거 공부할거 산더미인데 회사에서는 네트워크 지식도 딸리고 아이고...
하여간 나중에 제발 다시 까먹지마라... ㅠㅠ
참고
https://martinfowler.com/bliki/TellDontAsk.html
https://docs.oracle.com/javase/tutorial/java/concepts/interface.html
'programming language > Java' 카테고리의 다른 글
[Java] 객체지향 연습 1 - 상황 부여와 객체지향 예시 (0) | 2025.09.21 |
---|---|
[Java] Stream(스트림) - 2탄 (0) | 2025.05.08 |
[Java] 람다 표현식(Lambda Expreesion) - 2탄 (0) | 2025.05.01 |
[Java] 스트림(Stream)이란? - 1탄 (1) | 2025.05.01 |
[Java] 익명 클래스(Anonymous Class) (0) | 2025.04.23 |