0.6.1 소프트웨어의 수명
소프트웨어는 하드웨어와 달리 시간이 지날수록 부품이 닳거나 소모되지 않습니다. 한 번 작성된 코드는 시스템 환경이 변하지 않는 한 지속적으로 동작 가능합니다. 그러나 소프트웨어의 경우 기능이 추가되고 코드 수정이 많이 발생합니다.
디자인 패턴을 적용하여 설계하는 목적 중 다른 하나는 유지 보수성입니다. 유지 보수성은 향후 추가되는 코드를 수정하기 위해 쉽게 변경할 수 있도록 쓰인 코드를 말합니다. 소프트웨어의 유지 보수 기간은 조금씩 다르지만 통상적으로 10년 정도를 말합니다.
0.6.2 방어적 설계
오랫동안 문제없이 유지 보수를 하기 위해서 변경 가능한 디자인(design for change)으로 설계해야 합니다. 코드를 작성하면서 어떤 부분이 향후 수정될 것으로 예측된다면, 해당 기능을 방어적으로 처리할 수 있도록 코드가 설계돼야 합니다.
소프트웨어는 방어적 설계를 위해 지속적으로 코드를 개선하는 리팩터링 작업을 실시합니다.
0.7 정리
코드를 개발할 때는 유지 보수성과 성능적인 부분을 고려해야 합니다. 하나의 작업 코드를 지속적으로 살펴보면 코드의 흐름을 빨리 파악할 수 있습니다.
하지만 시간이 지나고 다른 사람이 코드를 다시 보려면 이전 코드를 확인하는 학습 시간이 필요합니다. 디자인 패턴에 익숙해진 후 코드를 작성하면 과거의 코드나 새로운 코드를 학습하는 시간을 줄일 수 있습니다. 이러한 측면에서 디자인 패턴은 문제 해결 방법 외에도 개발 비용과 시간을 절약하는 데 매우 유용합니다.
디자인 패턴과 처리 성능은 별개의 문제입니다. 성능 최적화를 위해서는 많은 함수의 호출과 객체 간 호출이 적을수록 좋습니다. 하지만 디자인 패턴에서는 코드의 가독성과 유지 보수를 위해 객체의 메서드를 분리하며 호출도 자주 발생합니다. 패턴을 너무 많이 사용하면 잦은 메서드 호출로 인해 성능이 저하될 수도 있습니다.
Part 1 생성 패턴
- 팩토리 패턴
- 싱글턴 패턴
- 팩토리 메서드 패턴
- 추상 팩토리 패턴
- 빌더 패턴
- 프로토타입 패턴
디자인 패턴은 크게 3개의 파트로 나뉩니다. 그중 첫 번째로 알아볼 패턴은 생성 패턴입니다. 모든 객체지향 프로그램은 클래스 선언과 객체 생성에서 시작합니다. 생성 패턴은 선언된 클래스로 객체를 생성하는 방법에 대한 문제점과 해결책을 제안합니다.
객체 생성
객체지향 프로그램을 실행하기 위해서는 클래스를 선언하고 객체를 생성해야 합니다. 대표적으로 new 키워드를 통해 생성합니다.
간단한 프로그램과 달리 큰 규모의 응용 프로그램을 객체지향 개발 방식으로 설계할 때는 생각보다 수많은 객체가 필요합니다. 그리고 객체의 관계를 설정합니다. 이때 작성 로직에서 직접 객체를 생성하고 관계를 설정하면 코드는 객체 간에 매우 강력한 결합 관계를 갖게 됩니다 (자세한 내용은 1장에서 다룹니다).
예를 들어 하나의 객체 내에서 새로운 객체를 생성하는데, 이렇게 직접 코드를 작성하여 객체를 생성하면 2개의 객체는 종속 관계를 형성합니다. 종속 관계를 가진 객체는 향후 확장과 유지 보수를 어렵게 하는 원인이 됩니다.
생성 패턴은 객체 간 강력한 결합 관계를 느슨한 결합으로 변경하는 설계 기법입니다. 이로 인해 느슨한 결합으로 변경된 객체는 확장을 보다 유연하게 하고 유지 보수를 편리하게 합니다.
관계 설정
객체지향 프로그램에서 객체는 관계를 형성합니다. 객체의 관계를 고려하여 언제 생성할지, 어떤 과정에 의해 생성할지를 생각한 후 좀 더 체계적으로 코드를 설계해야 합니다. 객체지향 프로그램에서 관계는 매우 중요한 설계 기준이 됩니다.
객체의 종류는 크게 상속을 이용하는 단일 객체와 다른 객체를 포함하는 복합 객체가 있습니다. 객체를 설계할 때는 어떤 유형의 객체를 생성할지 미리 정의하는 것이 중요합니다. 최근 객체지향은 복합 객체를 활용한 생성 방법을 더 선호하는 추세입니다.
추상화
과거와 달리 최근에는 프로그램이 대형화됨에 따라 큰 규모의 코드를 개발하고 협업하기 위해 추상화라는 기법을 사용합니다. 추상화는 실제 코드를 개발하기 전에 구체적인 내용은 배제하고 개략적인 정보만 선언하는 것입니다. 추상화로 선언된 코드는 실제 내용이 없어도 미리 선언된 정보만 이용하여 코드를 작성할 수 있습니다.
[자전거 이미지] --- 추상화 ---> [자전거 아이콘/도형]
추상화 작업은 추상적 개념과 실제 코드를 분리하는 효과가 있습니다. 개발 과정에서 클래스를 선언하고 실제 코드를 분리해 협업 코드를 작성합니다. 추상화를 통한 협업은 향후 개발 중인 코드를 예정하고, 선언만으로 주변 기능을 작성할 수 있다는 것이 장점입니다.
패턴
코드 작성 시 객체를 생성하는 방법은 매우 다양합니다. 생성 패턴에서는 객체의 생성 원리와 이를 활용한 객체의 생성 방법을 알아봅니다. 생성 패턴은 목적과 과정에 따라 6가지로 분류됩니다.
┌─── 팩토리 ────> 팩토리 메서드 ────> 추상 팩토리 ────> 빌더
│
[ 생성 패턴 ] ────┼─── 싱글턴
│
└─── 프로토타입
팩토리 패턴
학습하기 객체의 생성 동작을 별도 클래스로 분리하여 처리합니다. 또는 별도의 메서드를 호출하여 객체의 생성 동작을 처리합니다.
싱글턴 패턴
학습하기 선언된 클래스로 복수의 객체를 생성할 수 없도록 제한합니다. 제한된 단일 객체는 공유와 충돌을 방지합니다.
팩토리 메서드 패턴
학습하기 팩토리를 확장한 패턴입니다. 팩토리 패턴에 추상화를 결합하여 객체의 생성과 사용을 분리합니다. 팩토리 패턴은 선언된 클래스의 객체를 직접 코드로 생성하지 않고 별도로 준비한 추상 메서드에 생성요청을 위임합니다.
추상 팩토리 패턴
학습하기 팩토리 메서드를 확장한 패턴입니다. 팩토리 메서드보다 좀 더 큰 그룹 단위 객체를 생성 관리합니다. 추상 팩토리 패턴은 팩토리에 인터페이스를 적용하여 객체를 생성합니다. 팩토리를 팩토리에 군(family)으로 변경합니다.
빌더 패턴
학습하기 추상 팩토리를 확장한 패턴입니다. 복잡한 구조의 복합 객체를 빌더 패턴으로 생성합니다. 복합 객체를 생성하기 위한 단계를 정의하고, 각 단계별 수행 동작을 변경할 수 있습니다.
프로토타입 패턴
학습하기 새로운 객체를 생성하지 않고 기존의 객체를 복제합니다. 복잡한 구조의 객체를 새로 생성하는 것은 많은 자원을 소모합니다. 프로토타입 패턴은 객체를 새로 생성하지 않고 복제를 통해 자원을 절약하는 패턴입니다.
지금까지 6가지 생성 패턴을 간략하게 알아보았습니다. 생성 패턴은 목적과 과정 외에 매개변수에 의한 생성 방법과 합성에 의한 객체 생성 방법으로도 구분합니다.
매개변수에 의한 생성 방식은 상속을 통해 서브 클래스에서 객체 생성을 담당합니다. 팩토리 메서드 패턴이 대표적입니다.
합성에 의한 방식으로는 추상 팩토리 패턴, 빌더 패턴, 프로토타입 패턴이 있습니다. 이 3가지 패턴의 경우 객체 생성은 동일하나 객체를 생성하는 관점에 차이가 있습니다. 추상 팩토리는 여러 클래스의 군을 처리하는 반면, 빌더는 객체를 생성하는 복잡한 과정에 관점을 둡니다. 프로토타입 패턴은 어렵게 만들어진 객체의 중복 처리 자원을 배제하고 복사본을 통해 간편하게 처리하기 위한 패턴입니다.