프로그래밍 입문

클래스와 인스턴스와 객체

토픽 프로그래밍 입문 > Java 언어 > Java 기본 과정

메소드화

프로그래밍의 기본은 중복을 제거하는 것이다. 이 중복을 제거하기 위한 방법으로 고려해볼 수 있는 기능이 메소드. 로직을 메소드로 만들면 코드의 양을 줄일 수 있고, 문제가 생겼을 때 원인을 더 쉽게 찾을 수 있다. 아래의 코드는 위의 코드를 메소드화시킨 예제다.

 

public class CalculatorDemo2 {

public static void sum(int left, int right) {

System.out.println(left + right);

}

public static void main(String[] args) {

sum(10, 20);

sum(20, 40);

}

}

 

그런데 똑같은 수를 이용해서 더하기 뿐 아니라 평균도 구해야 한다면 어떻게 해야할까? 아래와 같이 할 수 있을 것이다. 입력값(left, right)을 변수화시키고 메소드들(sum, avg)가 이 값을 사용하면 코드의 양을 줄일 수 있게 된다.

 

public class ClaculatorDemo3 {

public static void avg(int left, int right) {

System.out.println((left + right) / 2);

}

public static void sum(int left, int right) {

System.out.println(left + right);

}

public static void main(String[] args) {

int left, right;

left = 10; right = 20;

sum(left, right);

avg(left, right);

 

left = 20; right = 40;

sum(left, right);

avg(left, right);

}

}

 

 객체화

코드가 복잡해지기 시작한다.

지금은 계산과 관련된 로직 밖에 없지만, 만약에 위의 코드에 데이터베이스에서 정보를 가져오는 로직이나결과를 그래프로 표시하는 로직과 같은 것이 함께 위치한다면 코드는 점점 복잡해 질 것이다. 그러다 누군가 변수 left, right의 의미를 계산을 위한 좌항과 우항이 아니라 그래프의 디자인을 변경하는 코드로 사용하거나, 메소드 sum을 더하기가 아니라 요약(summary) 정보를 그래프로 표시하는 의미로 사용하게 된다면 어떻게 될까? 하나의 프로그램 안에서 메소드나 변수의 의미가 달라지게 되는 것이다.

코드가 복잡해짐에 따라서 버그는 많아지고, 팀웍은 서서히 깨지기 시작할 것이다. 여러분이 언어의 설계자라면 이런 상황을 완화하기 위한 고민을 시작할 것이다. 이런 맥락에서 객체 지향이라는 개념이 등장하기 시작하는 것이다.

객체 지향은 많은 선배 프로그래머들에 의해서 만들어졌기 때문에 다양한 의도가 반영된 프로그래밍 패러다임이다

객체 지향의 핵심은 연관되어 있는 변수와 메소드를 하나의 그룹으로 묶어서 그룹핑하는 것이다.

  

메소드 sum avg는 변수 left right와 서로 연관 되어 있다. 또한 합계와 평균을 구하는 작업은 다른 에플리케이션에서도 사용할 수 있는 기능이다. 이것들을 그룹핑해서 하나의 부품으로 만들면 필요할 때마다 반복적으로 사용할 수 있을 것이다. 객체를 만들 때가 된 것이다.

 

class Calculator{

int left, right;

 

public void setOprands(int left, int right){

this.left = left;

this.right = right;

}

public void sum(){

System.out.println(this.left+this.right);

}

public void avg(){

System.out.println((this.left+this.right)/2);

}

}

 

public class CalculatorDemo4 {

public static void main(String[] args) {

Calculator c1 = new Calculator();

c1.setOprands(10, 20);

c1.sum();

c1.avg();

 

Calculator c2 = new Calculator();

c2.setOprands(20, 40);

c2.sum();

c2.avg();

}

}

 

클래스

위의 예에서 변수 left right, 메소드 sum avg는 연관되어 있는 로직이다. 이 로직들의 연관성은 계산을 하기 위한 것이다. 그래서 필자는 이 로직들을 대표하는 이름을 계산기라는 의미의 Calculator라고 정하고 이것들을 Calculator이라는 이름으로 그룹핑하고 싶다. 이럴 때 사용하는 키워드가 class이다. 이렇게 해서 더하기(sum)와 평균(avg)를 계산 할 수 있는 클래스가 만들어졌다. 클래스는 아래와 같이 정의 할 수 있다.

클래스는 연관되어 있는 변수와 메소드의 집합이다.

 

 

인스턴스

이제 클래스를 사용하는 방법을 알아보자. 클래스는 일종의 설계도다. 클래스를 정의하는 것 자체로는 할 수 있는 일이 많지 않다. 설계도를 구체적인 제품으로 만들어야 한다. 그 때 사용하는 키워드가 new이다

new Calculator()은 클래스 Calculator를 구체적인 제품으로 만드는 명령이다. 이렇게 만들어진 구체적인 제품을 인스턴스(instance)라고 부른다. 아래의 관계를 기억하자.

o 클래스 : 설계도

o 인스턴스 : 제품

위의 코드는 new를 이용해서 만든 인스턴스를 변수 c1에 담고 있다. 변수 c1에 인스턴스를 담은 이유는 c1을 통해서 인스턴스를 제어해야 하기 때문이다. 그런데 c1 앞에 Caculator가 위치하고 있다. 지금까지 우리는 여러가지 변수를 선언해왔다   

그럼 아래와 같은 구문은 변수명 c1의 데이터 타입 이 무엇이라는 의미일까?

Calculator c1

c1은 Calculator형 변수라는 의미다. 즉 클래스를 만든다는 것은 사용자 정의 데이터 타입을 만드는 것과 같은 의미다. 클래스와 인스턴스는 설계도와 제품이라고 설명했다. 그럼 객체는 클래스일까 인스턴스일까? 다소 논란이 있지만 일반적으로 설계도인 클래스가 구체적인 실체인 인스턴스가 되었을 때 객체라고 부른다

우리가 객체를 만들어서 사용하는 이유는 재활용성을 높이기 위해서다.

위의 코드를 보면 두개의 인스턴스를 각각 c1 c2에 담았다. 그리고 각각의 인스턴스에 소속된 메소드를 호출하고 있다. 각각의 인스턴스는 메소드 setOprands를 통해서 변수 left, right의 값을 설정하고 있다. 그 결과 인스턴스 c1 c2는  서로 다른 변수의 값을 내부적으로 가지고 있게 된다.

 

 메소드 setOprands 내에 this.이라는 것이 있다. this는 클래스를 통해서 만들어진 인스턴스 자신을 가리킨다. 위의 코드에서 left는 매개변수이고 이 변수는 setOprands 밖에서는 접근 할 수 없다. 반면에 this.left 4행에서 선언한 변수에 값을 설정하는 것이고 메소드 밖에서 선언한 변수는 인스턴스 내의 모든 메소드에서 접근이 가능하다. 이에 대한 이야기는 뒤에서 차차 하겠다

 

  

변수를 다른 말로는 상태(state)라고도 표현한다. c1.sum의 결과는 30, c2.sum의 결과는 60인 것을 통해서 알 수 있듯이 상태가 다른 객체를 대상으로 메소스를 실행시키면 다른 결과를 나타내게 된다. 메소드를 다른 말로는 행동(behave)라고도 표현한다.

- 변수 : 상태

- 메소드 : 행동

 

즉 하나의 클래스를 바탕으로 서로 다른 상태를 가진 인스턴스를 만들면 서로 다른 행동을 하게 된다는 것을 알 수 있다. 하나의 클래스가 여러개의 인스턴스가 될 수 있다는 점이 객체 지향이 제공하는 가장 기본적인 재활용성이라고 할 수 있다.

객체 지향의 객체를 하나의 작은 프로그램처럼 느껴보자. 프로그램 안에 객체라는 작은 프로그램을 만드는 것이다. 이것들을 레고 블럭처럼 쌓아서 웅장한 프로그램을 만드는 것이 객체 지향이 추구하는 바라고 할 수 있다.

 

댓글

댓글 본문