본문 바로가기
Programming/OOP

OOP(Object Oriented Programming) 기본 개념

by TinKerBellBass 2017. 8. 4.
728x90
반응형

참고 도서

스프링 입문을 위한 자바 객체 지향의 원리와 이해
국내도서
저자 : 김종민
출판 : 위키북스 2015.04.08
상세보기



1. 클래스, 객체, 인스턴스(Class, Object, Instance)

객체 지향 프로그래밍, 말 그대로 객체를 지향해서(이용해서) 프로그램을 짜는 것을 의미한다.
그럼 당연히 이 객체란 놈이 무엇인지 생각해 봐야 한다.
객체는 세상에 존재하는 물체를 의미한다. 생물도 가능하고 무생물도 가능하다.
프로그램의 세계에서 무생물은 현실세계와 달리 생물처럼 생명을 가지고 활동한다. 
의인화라고 볼 수 있다.
현실세계에서는 사람이 밥솥을 이용해서 밥을 한다고 표현하지만,
프로그램 세계에서는 사람이 밥솥에게 밥을 하라고 메시지를 보내고, 
그 메세지를 받은 밥솥이 밥을 한다.
밥솥이 살아있는 생물처럼 밥을 하는 동작을 행하는 것이다.

class 사람{
밥솥 쿠쿠 = new 밥솥( );
밥솥.밥을해라( );
}

class 밥솥{
public void 밥을해라( ){
System.out.print("열심히 밥을 만들어 냅니다");
}
}

라는 코드를 떠올려 보면 이해가 될 것이다.

위의 코드에서 사람은 밥솥에게 밥을 해라고 시킬 역할과 책임을 가지고 있으며,
밥솥은 열심히 밥을 만들어 내야 할 역할과 책임이 있다.
사람은 밥솥에게 밥을해라 라는 메시지를 보내 밥솥이 해야 할 역할과 책임을 다하게 하고 있다.

이렇게 객체 지향 프로그래밍에서 객체들의 고유의 역할과 책임을 가지고,
메시지를 통해 서로 협력하며
프로그램 세계를 만들어 나간다.

그럼 클래스, 객체, 인스턴스의 개념에 대해 알아보자.
먼저 객체는 어떠한 특징(속성, 기능)을 가지고 구분할 수 있는 물체이다.
짱좋은티비 라는 객체와 그냥저냥티비 라는 객체가 있다.
짱좋은티비는 100인치 화면, 제조사는 냥냥 이라는 특징과 
전원켠다, 전원끈다 라는 기능을 가지고
그냥저냥티비는 20인치 화면, 제조사는 멍멍 이라는 특징과
전원켠다, 전원끈다 라는 기능을 가지고 있다고 가정해 보자.
두 객체가 가지는 특징을 가지고 우리는 두 객체를 구분해 낼 수 있다.
객체는 어떠한 속성과 기능을 가지고 구분해 낼 수 있는 물체이다.

다음으로, 클래스는 객체들을 묶어서 분류할 수 있게 일반화 시킨 것이다.
짱좋은티비, 그냥저냥티비 두 객체를 일반화 시켜서 티비라는 클래스를 만들어 보자.

class 티비{
Int 화면크기;
Stirng 제조회사;
boolean 전원;

public 티비(Int 화면크기, String 제조회사){
this.화면크기 = 화면크기;
this.제조회사 = 제조회사;
}

public void 전원켠다( ){
전원 = true;
}
public void 전원끈다( ){
전원 = false;
 
}

두 객체를 일반화 시키면 이런 코드를 만들 수 있다.
그럼 이 일반화 된 클래스를 이용해서 구분 할 수 있는 특징을 가지는 객체를 만들어 보자.

티비 짱좋은티비 = new 티비(100, "냥냥", true);
100인치 화면, 제조사 냥냥인 티비 객체를 만들어서 티비 역할을 할 수 있는 짱좋은 티비라고 한다.

티비 그냥저냥티비 = new 티비(20, "멍멍", true);
20인치 화면, 제조사 멍멍인 티비 객체를 만들어서 티비 역할을 할 수 있는 그냥저냥 티비라고 한다.

이렇게 서로 다른 고유의 특징(속성, 기능)을 가지고 있는 물체의 특징을 묶어내서 
분류(속성과 기능을 뽑아냄)할 수 있게 일반화 한 것이 클래스이고,
일반화 한 클래스에서 고유의 특징을 가지고 구분할 수 있는 객체를 만들어 낸다.
그리고 클래스를 통해 만들어낸 객체를 특별하게 인스턴스라고 부른다.

그럼 소나타는 클래스일까, 객체일까?
클래스이다.
소나타라는 클래스에는 제조사 현대, 색깔, 변속기종류, 시트종류, 연료종류, 소유자이름, 달린다, 멈춘다, 방향을바꾼다 같은
속성과 기능이 정의되어 있을 것이다. 
소나타 클래스는 색깔은 빨간색, 변속기는 수동, 시트는 인조가죽, 연료는 가솔린, 소유자는 팅커벨, 달린다, 멈춘다, 방향을 바꾼다는 속성과 기능을 가지는 팅커벨의소나타 라는 객체를 만들어 낼 수 도 있고,
색깔은 검은색, 변속기는 자동, 시트는 패브릭, 연료는 가스, 소유자는 피터팬, 달린다, 멈춘다, 방향을 바꾼다는 속성과 기능을
가지는 피터팬의소나타 라는 객체를 만들어 낼 수 도 있다.
각각의 고유한 특징(속성, 기능)을 가지는 객체 중에서 소나타라고 분류할 수 있는 특징을 뽑아내고 일반화 시켜서
소나타 라는 클래스를 만들 수 있는 것이다. 

몇 가지 예를 더 들어보면,
클래스 사람 - 객체 송지효, 객체 전지현, 객체 손나은, 객체 전효성, 객체 송지은.... 
클래스 건담 - 객체 키라가 타는 프리덤 건담, 객체 아무로가 타는 1세대 건담, 객체 미카즈키가 타는 건담 바르바토스...

2. 상속(inherit) 인터페이스(interface)

상속(inherit)은 확장(extend)으로 이해해야 한다.
실제로 자바에는 inherits 이라는 예약어는 없고 extends 라는 예약어가 있다.
 
화면크기, 제조회사, 터치스크린기능 이라는 속성을 가지는 티비라는 클래스가 있다.
그런데 캡션기능(영어 자막, 영어와 일어자막 등)을 가지는 티비가 탄생했고, 
플렉시블화면(종이접기 처럼 접히는 플렉시블, 둥글게 말 수 있는 플렉시블 등)을 가지는 티비가 탄생했다.
새롭게 탄생한 이 두 티비를 일반화 하여 
속성으로 화면크기, 제조사, 어떤캡션기능을 속성으로, 
전원켠다, 전원끈다를 기능으로 가지는 캡션티비 클래스를 만들고,
속성으로 화면크기, 제조사, 어떤플렉시블화면을 속성으로, 
전원켠다, 전원끈다를 기능으로 가지는 플렉시블티비 클래스를 만들었다.
두 클래스 모두 화면크기, 제조사 속성이 있고 전원켠다, 전원끈다 기능이 있고, 
이 속성과 기능은 티비라는 클래스가 가지고 있다.

티비 클래스를 슈퍼클래스(super class)로 지정하고, 
캡션티비, 플렉시블티비를 서브클래스(sub class)로 지정하여 슈퍼클래스인 티비를 상속시킨다.

class 티비{
Int 화면크기;
Stirng 제조회사;
boolean 전원;

public 티비(Int 화면크기, String 제조회사){
this.화면크기 = 화면크기;
this.제조회사 = 제조회사;
}

public void 전원켠다( ){
전원 = true;
}
public void 전원끈다( ){
전원 = false;
 
}

class 캡션티비 extends 티비{
String 어떤캡션기능;

public 캡션티비(Int 화면크기, String 제조회사, String 어떤캡션기능){
super(화면크기, 제조회사);
this.어떤캡션기능 = 어떤캡션기능;
}
}

class 플렉시블티비 extends 티비{
String 어떤플렉시블;

public 캡션티비(Int 화면크기, String 제조회사, String 어떤플렉시블){
super(화면크기, 제조회사);
this.어떤플렉시블 = 어떤플렉시블;
}
}

코드로 나타내면 이렇게 될 것이다.

즉 서브 클래스는 슈퍼 클래스의 속성을 다 가지고 있으면서, 슈퍼 클래스에 없는 속성을 추가하여 확장한 것이고,
이것을 상속(확장)이라고 한다.

다음으로 인터페이스는 어떤 기능을 확장시킬 수 있는 기능을 한다.
인터페이스의 구현한 클래스는 반드시 인터페이스의 기능을 써야 한다.
그렇기 때문에 인터페이스를 구현한 클래스는 반드시 인터페이스에 정의된 기능을 가진다.

캡션티비에 터치스크린 기능을 추가해 보자.

class 티비{
Int 화면크기;
Stirng 제조회사;
boolean 전원;

public 티비(Int 화면크기, String 제조회사){
this.화면크기 = 화면크기;
this.제조회사 = 제조회사;
}

public void 전원켠다( ){
전원 = true;
}
public void 전원끈다( ){
전원 = false;
 
}

interface 터치할수있는{
static int 감도;

public abstract void 감도조절( );
}

class 캡션티비 extends 티비 implements 터치할수있는{
String 어떤캡션기능;

public 캡션티비(Int 화면크기, String 제조회사, String 어떤캡션기능){
super(화면크기, 제조회사);
this.어떤캡션기능 = 어떤캡션기능;
}

public void 감도조절( ){
감도 = 8;
}
}

이제 캡션티비 클래스에서 만들어지는 객체는 티비의 속성과 기능을 모두 사용할 수 있으며,
캡션 티비만의 어떤캡션기능이라는 속성과
터치할수있는 기능을 가지며, 터치감도를 조절할 수 있다.

자바는 다중 상속을 허용하지 않기 때문에 인터페이스를 이용하여 다중 상속 비슷한 효과를 낸다.
여기서 인터페이스는 클래스가 가져야 할 기능을 정의하고 있고, 그 기능을 어떻게 구현할 것인가는
구현하고 있는 클래스가 결정한다.

JDBC 인터페이스는 데이터베이스를 연결하고 구동하는 기능을 가진 인터페이스이다.
이 인터페이스를 오라클로 구현할지, MySQL로 구현할지는 구현하는 클래스에서 결정하면 되는 것이다.

3. 다형성(polymorphism)

다형성은 슈퍼클래스를 상속하고 있는 서브클래스들이 슈퍼클래스의 역할을 할 수 있다는 것과,
인터페이스를 구현하고 있는 클래스가 인터페이스의 기능을 할 수 있는 것을 의미한다.

캡션티비 끝내주는티비 = new 캡션티비( );
캡션티비 객체를 만들어서 캡션티비 역할을 할 수 있는 끝내주는티비라고 한다.

플렉서블티비 작살나는티비 = new 플렉서블티비( );
플렉서블티비 객체를 만들어서 플렉서블티비 역할을 할 수 있는 작살나는티비라고 한다.

티비 끝내주는티비 = new 캡션티비( );
캡션티비 객체를 만들어서 티비 역할을 할 수 있는 끝내주는티비라고 한다.

티비 작살나는티비 = new 플렉서블티비( );
플렉서블티비 객체를 만들어서 티비 역할을 할 수 있는 작살나는티비라고 한다. 

터치할수있는 끝내주는 티비 = new 캡션티비( );
캡션티비 객체를 만들어서 터치할 수 있는 기능이 있는 끝내주는 티비라고 한다.

이렇게 서브 클래스는 슈퍼 클래스의 역할을 해낼 수 있고,
인터페이스를 구현한 클래스는 인터페이스의 기능을 해낼 수 있다.

주의할 것은 상속의 경우,
끝내주는티비는 캡션티비 객체지만, 
티비 끝내주는티비 = new 캡션티비( ); 와 같이 객체를 만들면
티비의 역할을 하므로 티비 클래스에 있는 속성과 기능만 쓸 수 있다.
(캡션티비)끝내주는티비 처럼 형변환을 통해 캡션티비의 기능을 쓸 수 있다.
여기서 형변환의 의미는 끝내주는티비를 캡션티비 역할을 할 수 있게 만드는 것이다.

그리고 인터페이스의 경우 끝내주는 티비를
터치할수있는 끝내주는 티비 = new 캡션티비( ); 와 같이 객체를 만들면
터치할 수 있는 기능을 가진 캡션티비 역할을 하는 캡션티비 객체를 만든다고 생각하면 되기 때문에,
캡션티비의 모든 속성과 기능을 사용할 수 있고,
반드시 터치할 수 있는 기능을 사용해야 한다.

4. overloading / overriding

오버로딩은 같은 클래스 내에서 같은 이름의 메소드를 사용해 다양하게 들어오는 매개 변수를 처리하기 위한 것이다.

class Caculator{
public void add(int a, int b){
System.out.println(a+b);
}
}
더하기는 정수끼리만 더해지는 것은 아니기 때문에, 만약 오버로딩이 없다면,

class Caculator{
public void addFloat(float a, float b){
System.out.println(a+b);
}
}
와 같이 메소드 이름을 바꾸어 정의해야 할 것이다. 이러면 사용자가 덧셈을 할 때, 
어떤 메소드를 불러야 할지 고민해야 한다.
그러나 자바는 오버로딩을 가능하므로 위 메소드는

class Caculator{
public void add(float a, float b){
System.out.println(a+b);
}
}
와 같이 정의할 수 있다.
add 메소드가 실행 될 때, 컴파일러는 매개 변수의 타입을 판단해서 거기에 맞는 메소드를 호출해 준다.

오버라이딩은 슈퍼클래스의 메소드를 서브클래스가 재정의 하는 것이다.

class SuperClass{
public void display( ){
System.out.println("I am superclass");
}
}

class SubClass extends SuperClass{
@Overriding
public void display( ){
System.out.println("I am subclass");
}
}

이렇게 오버라이딩 된 메소드가 있다면,

SubClass sub = new SubClass( );
sub.display( );

를 실행하면 I am subclass 가 출력 될 것인데, 고민해 봐야 할 것은

SuperClass sub = new SubClass( );
sub.display( );
가 되면 무엇이 출력될까?
이 때도 I am subclass 가 출력된다.

이와 같이 오버라이딩은 다형성과 아주 밀접한 관계가 있다.
오버라이딩을 통한 다형성은 
같은 메시지를 수신하더라도 수신자에 따라 다양한 기능을 수행한다는 것이 핵심 개념이다.

5. 상속과 인터페이스에서 고민해 봐야 할 것

같은 슈퍼클래스를 상속하고 있는 서브클래스들은 모두 슈퍼클래스의 속성과 기능을 가지고 있다.
그래서 슈퍼클래스에는 서브클래스들이 가지는 공통되는 속성과 기능이 많으면 좋다고 생각할 수 있다.
슈퍼클래스에 공통되는 속성과 기능이 많으면 서브클래스들의 코드는 중복이 줄어들고 간결해 질 것이기 때문이다.

그리고 인터페이스에는 한 가지 이상의 기능이 정의되어 있지 않는 것이 좋다.
새는 날 수 있다. 그래서 날 수 있는 기능을 가진 새의 특징을 가진 클래스를 만든다고 하면,
날 수 있는 기능 한 가지만 구현하도록 강제되어 있는 인터페이스를 구현 시키면 된다.
그러나 인터페이스가 날 수 있는, 헤엄칠 수 있는 두 가지 기능을 가지고 있다면,
이 인터페이스를 구현시킬 클래스를 선택할 때 신중해야 할 것이다.
그래서 자바는 다중 상속은 허용하지 않지만, 여러 개의 인터페이스를 구현하는 것은 허락하고 있는 것이다.



728x90
반응형

댓글