
모델이 무엇인가?
프로그래밍을 하면서 가장 많이 사용했던 단어인데 알쏭달쏭한 단어였다. ‘도메인 모델’, ‘서비스 모델’ 등등 많은 책에서 접했던 단어이다. 사전적 의미로 모델이란 ‘본보기가 되는 대상이나 모범’이다. 나는 모델이라고 하면 멋진 옷을 입고 당당하게 워킹을 하는 ‘패션 모델’만 떠올랐다. 결국 ‘패션 모델’이 하는 역할은 본인이 입은 옷을 소화해내며 옷에 대한 느낌과 어떻게 입어야하는지에 본보기가 되는 것이었다. 프로그래밍에서 칭하는 모델도 같다. 우리는 기획을 할 때 프로그래밍으로 표현해야 할 영역들이 있다. 그 영역을 명확하게 보여주는 모범이 모델이라고 하는 것이다.
예를 들어보자. 프로그래머를 모델로 표현하고 싶다면 먼저 ‘프로그래머’의 본연의 의미를 생각해 본다. 프로그래머는 이름과 다루는 언어, 경력을 표현을 하게 된다면 그것이 ‘프로그래머’를 칭하는 모델이 되는 것이다.
public class Programmer{
private String name;
private String language;
private int age;
}
추상화
객체지향 프로그래밍을 하며 가장 중요하게 생각하는 요소이다. 처음 많은 개발자들이 추상화가 중요하다라고 이야기했을 때 그 의미를 이해하지 못했다. 추상화라는 개념을 이해하고 프로그래밍을 했을 때 조금 더 나의 코딩은 객체지향적으로 다가간 것 같다.
추상화는 추상적 특징을 파악해 인식의 대상으로 삼는 행위라고 한다. 예를 들어 영화관 예매 시스템을 만든다고 가정해보자. 일단 영화관 티켓을 사기 위해서는 매표소를 가야 한다. 그래서 Ticket이라는 모델을 제공해주는 곳을 매표소라고 추상화를 시켜 개발을 하는 것이다. 그렇게 되면 조금 더 ‘매표소’라는 모델의 역할이 명확해질 것이다.
public class TicketStand{
private List<Ticket> ticket;
public void sellTicket(){...}
}
또한, 추상화라는 의미는 일반화라는 의미도 있다. 일반화란 아우디, 벤츠, 현대 등등을 바라봤을 때 ‘자동차’라고 일반화를 하는 것이다. 프로그래밍에서는 ‘자동차’라는 클래스를 만들고 상속 받아 아우디, 벤츠, 현대의 모델을 각각 특수화를 시킨다.
캡슐화
캡슐화하면 대표적으로 따라나오는 장점은 정보 은닉을 통한 높은 응집도와 낮은 결합도이다.(?!)
처음에는 이게 대체 무슨 말인가 했다… 정보 은닉은 뭐하러 하는 건데? 다른 개발자들이 내 코드를 못 보게 만든다는 것인가?? 라는 생각도 했다.
정보 은닉이란 개발자가 아닌… 다른 클래스가 또 다른 클래스의 대한 정보를 알 필요가 없다는 것이다. 운전자와 차 사이를 예를 들어 보겠다. 운전자는 차의 엔진이 어떻게 구성되어 있고 등등 차에 대한 정보를 모른다고 그 차를 운전을 못하는 것은 아니다. 운전자는 그냥 엑셀을 밟으면 나가고 브레이크를 밟으면 슨다 라는 최소한의 정보로 운전이 가능하다. 만일 차의 엔진을 세부 구성을 알아야 운전이 가능하다라고 가정 했으면 아마 운전자는 평생 차를 바꾸지 않았을 것이다.
이와 같이 정보 은닉은 한 클래스가 다른 클래스의 세부 구성을 몰라도 그 클래스의 편리함을 이용할 수 있다는 것이다. 만일 세부 구성을 알아야지만 이용이 가능하다면 다른 모듈, 즉, 더 나은 비슷한 기능을 사용하고 싶어도 위에 언급한 운전자처럼 바꾸기가 애매했을 것이다. 이것이 정보 은닉을 통한 높은 응집도와 낮은 결합도인 것이다.
상속
상속을 잘 사용한다면 다형성과 같은 기법으로 정말 좋은 객체지향적 구조가 만들어지지만 오용을 한다면 코드는 한층 더 복잡해지고 유지보수는 더 힘들어질 수도 있다. 그래서 ‘피터 코드’는 상속의 오용을 막기위해 몇가지 규칙을 만들었다.
- 자식 클래스와 부모 클래스 사이는 ‘역할 수행(is role played by)’ 관계가 아니어야 한다.
- 한 클래스의 인스턴스는 다른 서브 클래스의 객체로 변환할 필요가 절대 없어야 한다.
- 자식 클래스가 부모 클래스의 책임을 무시하거나 재정의하지 않고 확장만 수행해야 한다.
- 자식 클래스가 단지 일부 기능을 재사용 할목적으로 유틸리티 역할을 수행하는 클래스를 상속하지 않아야 한다.
- 자식 클래스가 ‘역할’, ‘트랜잭션’, ‘디바이스’ 등을 특수화해야한다.
SOLID
단일 책임 원칙 (Single Responsibility Principle)
객체 지향의 설계에서 가장 중요한 원칙인 것 같다. 말 그대로 단 하나의 책임만을 가져야 한다는 의미
개방-폐쇄 원칙 (Open-Closed Principle)
기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계가 되어야 한다는 뜻이다.
리스코프 치환 원칙 (Liskov Substitution Principle)
일반화 관계에 대한 이야기다. 자식 클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야 한다는 이야기이다.
인터페이스 분리 원칙 (Interface Segregation Principle)
클라이언트 자신이 이용하지 않는 기능에는 영향을 받지 않아야 하는 내용이 담겨있는 원칙이다. 즉, 범용의 인터페이스보다는 클라이언트에 특화된 인터페이스를 제공하는 것이다.
의존 역전 원칙 (Dependency Inversion Principle)
외부에서 사용하는 곳에서 객체를 넣어주어 의존성을 역전시켜 주는 원칙이다. (스프링에서 의존성 주입과 많이 사용이 됨)