이 장에선 객체지향의 개념을 소개하는 파트이다.
개념은 끊임없이 진화한다. 그리고 이런 진화적 측면이 개념에 초점을 맞추기 아주 적합하다.
개념은 일관성을 보이더라도 늘 새롭게 해석할 수 있으므로 아주 흥미로운 토론 거리가 될 수 있다.
역사적으로 객체지향 언어는 캡슐화, 상속 및 다형성으로 정의되어 있다.
고전적인 객체지향
따라서 한 언어가 이러한 특성을 따르지 않으면 객체지향언어가 아닌 것으로 간주한다.
저자는 세가지 개념에서 합성이라는 개념을 추가하여 총 4가지 개념을 말한다.
- 캡슐화(encapsulation)
- 상속(inheritance)
- 다형성(polymorphism)
- 합성(composition)
생각했던 대로 바로 등장하는 상속의 문제점..
다음 장에서 다룰 예정이지만 많은 개발자들은 최대한 상속을 피하려 한다.
여기서도 등장하는 생각이지만 is a의 개념.. 좋은 코드 나쁜 코드에서도 논쟁이였지만 상속에 대한 말은 아직도 다양하게 나오는 것 같다.
- 레거시 시스템(legacy system): 구형,기존 시스템이라고 불림
구조적 프로그래밍과 객체지향적 프로그래밍은 서로 경쟁관계(대립)의 관계가 아니다.
즉, 객체지향 코드는 구조적 코드를 대체하기 위한 것이 아니다.
객체지향적이지 않은 많은 레거시 시스템이 작업을 제대로 수행하고 있는데 굳이 변경하거나 교체해서 위험을 무릎쓸 이유가 있을까?
즉 프로그램이 잘 동작만 한다면 객체지향이든 절차지향이든 크게 상관이 없지만 완전히 새로 개발해야하는 상황이라면 객체지향 기술을 반드시 고려해야 한다.
어떤 경우에는 그렇게 할 수 밖에 없다.
최근 웹앱에서 처리에 대한 내용이 증가하면서 객체지향이 더욱 각광받고 있다.
따라서 대부분의 시스템이 새로 개발되고 있는 상황에서 레거시는 크게 문제가 되지 않는다.
문제가 있더라도 레거시를 객체 래퍼로 둘러싸는 경향이 있다.
- 객체 래퍼
다른 코드를 둘러싸는 객체지향 코드이다.
대부분의 객체지향을 선호하게 되면서 전송을 객체로 처리하는 방식으로 변경되았다.
객체지향의 장점을 생각하기 이전에 "객체란 무엇인가?"
이 질문은 단순하면서 복잡하다..
하지만 대부분의 사람들이 객체(물체)라는 관점에서 생각하며 산다는 관점에선 간단하다.
로버트 마틴은 사람들이 객체라는 관점에서 생각한다. 이라는 말을 마게팅 담당자가 지어낸 문구라는 의견이 있다.
사람을 볼 때 사람을 일종의 객체(object)로 간주하게 된다.
그리고 객체는 속성과 행위라는 두 가지 성분으로 정의된다.
사람에게는 눈 색, 나이, 키등과 같은 **속성(attributes)**이 있다.
또한 걷기, 말하기, 호흡하기 등 **행위(behaviors)**를 한다.
객체에 대한 기본적인 정의에 따르면 객체란 데이터와 행위라는 양면(both)을 포함하는 엔터티(entity)다.
양면이라는 단어는 객체지향 프로그래밍과 다른 프로그래밍 방법론과 주요한 차이점이다.
- 절차적 프로그래밍은 클래스라는 개념이 없기 때문에 다른 함수나 절차와 구별된다.
객체지향의 이점이 명확했지만 쉽게 도입하지 못한 이유는 절차적 프로그래밍이 잘 동작했기 때문이다.
절차지향은 데이터에 대한 접근을 제어하거나 예측하기가 어렵다는 매우매우 큰 단점이 있는 반면 객체지향방식에서는 데이터와 행위를 객체로 결합함으로써 이러한 데이터 문제를 해결할 수 있다.
- 적절한 설계: 제대로 설계된 객체지향 모델이라면 전역 데이터가 전혀 없을 것이라고 말할 수 있다.. 이로 인해 객체지향 시스템은 데이터 무결성이 달성된다.
객체는 자료구조나 정수, 문자열과 같은 기본 데이터 형식 이상의 것이다.
객체에는 속성을 나타내는데 사용되는 정수 및 문자열과 같은 엔터티가 들어 있지만, 행위를 나타내는 메서드도 들어 있다.
객체에서 메서드는 데이터에 대한 연산이나 그 밖의 연산을 수행하는데 사용된다.
더 중요한 것은 객체의 멤버(속성 멤버와 메서드 멤버)에 대한 접근을 제어할 수 있다는 점이다.
이것은 속성과 메서드에서 모두 일부 멤버가 다른 객체에 대해 숨겨질 수 있다는 점이다.
- 데이터 은닉: 객체지향 용어에서는 데이터를 속성이라고 하고 행위를 메서드라고 한다. 속성이나 메서드에 접근하지 못하게 제한하는 일을 데이터 은닉이라고 한다.
객체지향 용어로는 캡슐화라고 부른다.
Math클래스와 myObject클래스가 있다고 할 때 Math클래스의 멤버 변수 myInt1, myInt2을 합산한 결과에 접근하고 싶다면 myObject클래스는 Math의 sum메서드를 호출하여 값을 반환받는다.
여기서 잘 봐야하는 점이 myObject는 sum메서드의 동작방식을 알 필요가 없다.(알수없다.)
즉 이러한 설계를 가져가면 필요에 의해 Math에서 sum함수를 변경하게 되면 myObject를 수정할 필요가 없어진다.
책임을 온전하게 해당 객체가 담당하는 것이 핵심..
일반적으로 객체는 다른 객체의 내부 데이터를 조작해서는 안 된다.
일반적으로 큰 객체를 만들어서 작업하는 것 보다 작은 객체로 만들어 특정 작업만 담당하게 하는 것이 좋다.
절차적 프로그래밍은 일반적으로 시스템의 데이터를 다루는 연산과 데이터를 분리한다.
객체지향 프로그래밍은 데이터와 연산을 하나의 객체로 묶는다. (캡슐화)
객체란 객체지향 프로그램의 빌딩 블록이다.
객체지향 기술을 사용하는 프로그램은 기본적으로 객체들의 모음인 것이다.
객체 내에 저장된 데이터를 **속성(attribute)**이라고 한다.
객체가 수행할 수 있는 행위를 **메서드(method)**라고 한다.
- C#의 프로퍼티..
예제에서 나오는 프로퍼티보다 최근에는 자동구현 프로퍼티기능을 더 많이 사용하는 것 같다.
- 게터와 세터: 게터와 세터는 속성에 대한 접근을 제어하는 메서드다.
간혹 게터와 세터가 왜 필요한지 이해하기 어려운 경우가 있다.
예를 들어, 속성이 음수가 될 수 없는 경우 게터와 세터를 사용하여 이를 제어할 수 있다.
그 밖에도 객체지향의 정신을 그대로 가져갈려면 데이터를 직접 조작하면 안 되므로, 게터와 세터로 객체 데이터에 대한 접근 권한을 제어해야 한다.
우리는 메서드의 인터페이스만 보여주고 있을 뿐, 메서드의 구현을 보여주고 있지 않다는 점에 유념해야 한다.
- 메서드의 이름
- 메서드에 전달된 매개변수
- 메서드의 반환 형식
사용자가 메서드를 효과적으로 사용하기 위해 알아야 하는 요소
클래스란 객체를 만드는 탬플릿이다.
객체가 생성되면 우리는 객체가 인스턴스화되었다고 말한다.
클래스는 객체를 만드는 설계도다.
Person클래스
public class Person
{
private string name;
private string address;
public string getName()
{
return name;
}
public void setName(string name)
{
this.name = name;
}
public string getAddress()
{
return address;
}
public void setAddress(string address)
{
this.address = address;
}
}
- 속성: name, address가 속성이다.
- 메서드: getName, setName, getAddress, setAddress
메시지는 객체 간의 소통 매커니즘이다.
메시지는 객체가 다른 객체에게 요청을 보내는 것이다.
조금 거창해 보이지만 객체에서 다른 객체의 메서드를 호출하는 것이다.
클래스 다이어그램중 가장 많이 사용되는 UML클래스가 있다.
그렇다고 UML클래스 다이어그램을 사용해야만 한다는 것은 아니다.
꼭 사용할 필요는 없으며 직관적으로 이해할 수 있는 다이어그램을 사용하면 된다.
객체를 사용할 때의 주요 이점 중 하나는, 모든 속성과 행위를 객체에 나타낼 필요가 없다는 점이다.
좋은 객체지향 설계에서 객체는 여타 객체와 상호 작용하는 데 필요한 인터페이스만 타나내야 한다.
객체 사용과 관련이 없는 세부 사항을 그 밖의 객체들이 알 수 없도록 감추어야 한다.
캡슐화는 객체속에 속성뿐만 아니라 행위도 함께 들어 있다는 사실에 기반하여 정의할 수 있는 개념이다.
인터페이스는 객체가 다른 객체와 소통하는 방법을 정의한다.
- 비공개 데이터: 데이터의 은닉이 제대로 작동하려면 모든 속성을 private으로 선언해야 한다. 따라서 속성은 인터페이스의 일부가 아니다. public메서드들만이 클래스 인터페이스의 일부이다.
속성을 public으로 하게 되면 데이터의 은닉 개념이 깨진다.
공개 속성과 공개 메서드만 인터페이스로 간주한다.
사용자는 내부 구현부중 어떤 부분도 볼 수 없으며, 클래스 인터페이스를 통해서만 그 밖의 객체와 소통할 수 있다.
따라서 비공개로 정의된 게 어떤 것이든지 간에 사용자는 접근할 수 없으며, 비공개로 정의된 것들은 클래스의 내부 구현부의 일부로 간주된다.
usb 포트, 전기 단자와 같은 예
예제에서는 계산부분을 private로 선언하고, public으로 선언된 메서드를 통해서만 계산을 할 수 있도록 하였다.
이렇게 한번 더 둘러싼 이유는 이후에 계산부분만 수정이 되면 프로그램의 동작과정이 문제가 없고 모듈화의 기초가 되기 때문이다.
계산출력부분을 델리게이트로 두거나 인터페이스로 연결해두어서 다양한 계산에도 대응이 가능하다.
상속을 통해 클래스는 그 밖의 클래스들이 지닌 속성과 메서드를 물려받을 수 있다.
이를 통해 새로 만들려고 하는 클래스가 아닌 그 밖의 클래스들이 공통으로 지닌 속성과 행위를 추상화해 새 클래스를 만들 수 있다.
- 행위: 오늘날에는 행위를 인터페이스 안에 기술해 두는 경향이 있으며, 속성들을 상속하는게 일반적인 용례라는 점에 주목할 만하다.
슈퍼클래스, 서브클래스, 기반클래스, 파생클래스, 부모클래스, 자식클래스 등으로 불린다.
상속 트리는 상당히 커질 수 있다.
만약 포유류 클래스가 완성이 되고 이를 상속받는 강아지, 고양이, 사자 등등을 쉽게 추가할 수 있다.
코드의 중복도 줄고 좋아보인다.. 하지만
고양이의 경우 종에 따라 좀 더 추사화되어야 할 수 있다.
추상의 개념은 사람마다 주관적이므로 펭귄의 경우 새로 분류하는지(새 추상클래스의 경우 날 수 있다)
한가지 부모를 상속하면 단일 상속, 두개 이상의 부모를 상속하면 다중 상속이라고 한다.
도형의 경우 사각형은 도형이고, 원도 도형이다 즉, cicle is a shape이다.
이러한 명확한 관계를 is a
관계라고 한다.
다형성은 문자 그대로 다양한 현상을 의미하는 그리스어다.
다형성은 상속과 밀접하게 관련되어 있지만 종종 객체지향 기술의 가장 강력한 점 중에 하나로 여겨진다.
동적바인딩에 대한 이야기.. 상속받은 인터페이스를 오버라이딩하여 각 자식 클래스마다의 인터페이스를 가져가는 것
객체에 다른 객체가 들어있다고 생각하는 게 자연스럽다.
컴퓨터에는 그래픽카드와 키보드 및 드라이버가 들어있다.
컴퓨터도 객체로 간주할 수 있지만, 그 안에 담긴 그래픽카드, 키보드, 드라이버도 객체로 간주할 수 있다.
좀 더 직관적이게 컴퓨터를 열어 그래픽카드, 키보드, 드라이버를 꺼내보자.
이런 식으로 객체를 종종 그 밖의 객체들을 사용해 구축하거나 합성할 수 있는데, 이것이 합성이라는 개념이다.
상속과 마찬가지로 합성은 객체를 만드는 매커니즘을 제공한다.
실제로 필자는 클래스를 그 밖의 클래스를 사용해 작성하는 방법으로 상속과 합성 두 가지를 모두 사용한다.
자동차와 엔진의 관계를 생각해본다면 합성의 이점이 명확해진다.
car has a engine이다.
상속은 is-a의 관계를 표현하는데 적합하다.
합성은 has-a의 관계를 표현하는데 적합하다.
합성을 다른 말로 구성
으로도 많이 사용되는 듯 하다
과연 객체지향언어를 사용하는 사람들 중 고전적인 객체지향이 아닌 책에서 말하는 객체지향을 공부한 사람이 몇이나 될까..?
나는 1년간 객체지향언어를 사용했다고 말은 할 수 있지만 개념도 제대로 이해하지 못한 채 사용했던 것 같다..