본문 바로가기
Flutter/Dart 입문

[Dart] 10-1. 클래스(class)

by Couldi 2021. 10. 22.
반응형

21. 10. 22.

- Could -

 

이 글은 프로그래밍 입문을 Flutter 때문에 Dart로 시작하는 사람들을 위한 글입니다.
프로그래밍 언어가 가지고 있는 기본 컨셉 자체를 Dart라는 언어를 통해 설명하고,
많은 분들이 Flutter를 위해 학습한다고 생각해, 추후 Flutter 학습에 도움이 되는 방향으로 작성되었습니다.
1. 객체(Object)
2. 클래스(class)
3. 생성자(constructor)
4. 인스턴스(instance)

 

클래스를 이해하기 위해서는 총 4가지 단어를 제대로 이해를 해야한다.

  • 객체(Object)
  • 클래스(class)
  • 생성자(constructor)
  • 인스턴스(instance)

지난 시간에 객체는 명사라면서 뜬구름 잡는 소리를 했으니, 이제 본격적으로 객체가 뭔지부터 하나한 알아가보자.

 

1. 객체(Object)

객체라 부르기도 하고 오브젝트라고 부르기도 한다. 

 

https://ko.wikipedia.org/wiki/%EA%B0%9D%EC%B2%B4_(%EC%BB%B4%ED%93%A8%ED%84%B0_%EA%B3%BC%ED%95%99) 

 

객체 (컴퓨터 과학) - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

 

위키에서 내리는 객체의 정의는  '클래스의 인스턴스'다. 그럼 클래스는 뭐냐? 객체를 만들때 쓰는거다. 인스턴스는 뭐냐? 객체다.

이런식이다. 그냥 서로 엄청 관련있구나 정도만 깨닫게 되었을뿐 뭐가 뭔지 하나도 모르겠다.

 

객체(Object)란?

객체란 변수와 함수 등이 모여있는 코드 뭉치이다. 객체를 이해하기 위해 RPG게임을 떠올려보자. 어떤 비유보다 게임을 통한 설명이 가장 효과적이다. RPG 게임에 나오는 '주인공'이라는 이름의 캐릭터를 만들자. 이 '주인공'은 캐릭터명, HP, MP 등의 캐릭터 스탯이 있고, 공격 스킬과 방어 스킬을 가져야 한다. 이런 캐릭터를 코드를 짜서 만든다고 생각하면, 캐릭터 스탯들은 변수에 담고, 스킬들은 함수를 통해 구현하면 될꺼라는 생각이 든다.

하지만 우리가 지금까지 배운 내용으로는 변수와 함수를 만들 수 있을지는 몰라도, 이 '주인공'에 관련된 변수와 함수를 만들기에는 무리가 있다. 각각 변수와 함수로 정의는 내리겠지만, 전부 별개의 상자로 관리되고 있으니까.

 

String name = '주인공';
int hp = 100;
int mp = 100;

void attack() {
   print('attack!!');
}

void defence() {
    print('defence');
}

 

대충 코드를 짜면 위와 같은 식으로 짤 수 있다. 만약 이런 캐릭터가 100개, 1000개가 있으면 코드를 짤때 무슨 짓을 해야할까.

100개의 상자, 1000개의 상자를 만들고 하나하나 데이터를 넣는 작업을 한다면.. 프로그래밍을 하는건지 단순 노가다 작업을 하는건지 아리송해 질 것이다. 

만약 관련 있는 코드들을 '객체'라는 이름으로 묶어 관리하고, 안에 들어가는 변수와 함수들에 조금씩 변형을 주어 재사용할 수 있게 된다면 어떨까?

 

'주인공' 이라는 객체가 name, hp, mp와 같은 데이터를 가지고, attack과 defence라는 함수를 사용할 수 있는 코드의 구조를 짜두고, 그 구조를 반복해서 사용한다면 주인공1, 주인공2, 주인공3은 물론이고 코드를 응용해 다른 몹이나 NPC같은 다른 캐릭터들을 만드는 것도 가능해진다.

 

여기서 '주인공' 캐릭터가 의미하는 것이 바로 객체이다. 변수와 함수 등이 모여있는 코드 뭉치. 그럼 이제 객체를 만들어보자.

 

2. 클래스(Class)

객체를 만들기 위해서는 클래스를 알아야한다. 클래스에 대해서 학급에 비유해 설명하는 사람들도 있고, 게임 속 직업같은 것에 비유해 설명하는 사람들도 있다. 하지만 그런 설명보다 이 한 문장으로 클래스를 기억해 주었으면 한다.

'객체를 만들기 위한 설계도'

이케아에서 가구를 사면, 조립에 관한 설명서가 들어 있다. 이 설명서에는 보통 어떤것들이 적힐까? 구성품이 무엇인지, 어떻게 조립해야하는지, 완성 후에 어떻게 작동하는지 등. 경우에 따라서는 이 세가지가 다 적혀있을수도 있고, 몇개가 빠져있을 수도 있지만, 기본적으로 저 세가지가 적혀있으면 설계대로 제품을 만들어 사용할 수 있다.

우리가 이제 다루고자 하는 클래스도 '객체를 만들기 위한 설계도'이기에 이러한 내용이 담겨있어야, 컴퓨터가 알아보고 우리가 원하는 객체를 만들어 줄 수 있다.

간단하게 Human 이라는 클래스를 만들어 보도록하자.

class Human {
    // Instance variables
    String name;
    int hp;
    int mp;
    
    // 생성자(constructor)
    Human(String name, int hp, int mp) {
        this.name = name;
        this.hp = hp;
        this.mp = mp;
    }
    
    // 위의 생성자처럼 쓰는게 귀찮은 개발자들이 아래처럼 써도 괜찮게끔 이리 작업해두었다.
    // Dart에서도 아래처럼 constructor를 작성하는 것을 권장하지만 코드의 이해를 위해 위와 같은 코드를 작성해 두었다.
    // this 가 어떤 역할을 하는지 조사해보고 코드를 읽어보자.
    // Human(this.name, this.hp, this.mp)
    
    // Methods
    void attack() {
        print('attack!!');
    }
    
    void defence() {
        print('defence!!');
    }
}

 

class를 만들면 크게 3가지 부분 정도로 나눠볼 수 있다. (경우에 따라 조금씩 차이는 있을수 있지만 일반적인 구조가 그렇다.)

  • Instance variables
    생성될 객체(Instance)에 담겨야할 변수들이다. 예제에서는 주인공 캐릭터를 만들기 위해 필요한 데이터인 name과 hp, mp를 말한다. 주인공을 찍어내는 틀을 class라고 부르고, 찍혀나오는 주인공을 인스턴스(Instance)라고 부른다.
    객체를 만들때 필요한 재료들을 정의해둔다고 생각하면 편하다. 
  • constructor
    class를 정의했으면 이 class를 이용해 객체를 만들어 내야한다. 이때 변수들에 어떤 데이터들을 넣어서 만들지 정의해주는 부분이 constructor부분이다. 이부분을 어떻게 작성하느냐에 따라 새로운 객체 생성을 위해 어떤 데이터들을 집어넣어야하는지가 결정된다.
    위의 코드의 경우, name, hp, mp이 세가지 데이터를 받게끔 구조가 짜여있으며, 받은 데이터는 Human에 정의된 name, hp, mp 변수에 들어가게된다.
  • Methods
    동작해야할 함수들이다. 함수가 클래스안에 포함되거나 다른 구조체 안에 들어가게 되면, 이때는 함수가 아니라 메소드라고 부른다. 어디 소속 있는 함수구나 정도로 생각하면 된다.

위와 같이 세부분을 작성해주고, 추후 사용할때 Constructor를 이용해서 사용한다.

Human hero = Human('주인공', 100, 200)

 

일단 기본 구조는 변수를 정의할 때와 같다. 변수 안에 들어갈 데이터타입을 적고, 변수명을 적은 뒤 안에 대입할 데이터를 적는다.

생성자를 이용해 새로운 인스턴스를 만드는 것은 위와 아주 똑같은 과정이다. 먼저 사용할 클래스명을 적고, 인스턴스의 이름을 적는다. 이부분은 데이터를 넣을 변수를 만드는 과정과 동일하다. 그리고 생성자를 이용해 인스턴스를 생성하고 만들어둔 hero 상자에 집어넣는다.

 

DartPad를 이용해 작성하면 다음과 같다. 몇가지 주의사항이 있는데 class를 선언할때는 void main() 함수 밖에 작성해야 한다. 여기에는 또 설명하자면 많은 이유가 있지만, 지금은 클래스에 집중하기 위해서라도 그냥 그렇게 한다고만 알고 넘어가자. 클래스가 익숙해지고 난 후, class의 선언 위치를 어떻게 해야하는지 구글링을 통해 알아보기 바란다.

 

3. constructor(생성자)

생성자라고 해서 대단한거 같지만 전혀 그렇지 않다. class를 정의할 때 적는 설계도의 일부이며, 어떤 재료들을 넣어주세요. 적는 부분이다.

class Human {

    // 생성자(constructor)
    Human(String name, int hp, int mp) {
        this.name = name;
        this.hp = hp;
        this.mp = mp;
    }
    
    // 이렇게 더 많이 쓴다.
    Human(this.name, this.hp, this.mp)

}

 

생성자에만 집중해보자. class의 이름을 대문자로 짓는걸 주목하자. 클래스의 {} 안에서 생성자는 class의 이름과 똑같은 이름으로 적는다.

class 이름이 Human이니까 Human()으로 적어주는 거다. 만약  Elf거나 Dwarf였다면 Elf나 Dwarf로 적어줬어야한다.

그 이후 적는 내용은 함수를 정의할 때와 유사하다. () 안에는 생성자가 호출될때 받을 데이터들을 적어주고, {} 안에는 클래스 내에 정의된 instance variable안에 받은 데이터를 적어준다. 이때 사용되는 키워드가 this이다.

 

    // 생성자(constructor)
    Human(String name, int hp, int mp) {
        this.name = name;
        this.hp = hp;
        this.mp = mp;
    }

 

이 코드를 보자. String name, int hp, int mp를 받는다. 앞서 instance variable로 정의한 변수들과 변수명이 겹친다. 변수명을 다르게 하면 이해가 더 빠를 수도 있었겠지만, 데이터를 받아 instance variable에 넣는다는 걸 명확히 하기 위해 변수명을 똑같이 쓴다. (다르게 써도 상관은 없지만 많은 개발자들이 동일한 변수명을 선언한다.)

오른쪽에 잔뜩 뜬 에러메세지는 일단 무시하자.

생성자의 ()안에 정의한 변수명과 class안에 정의한 변수명이 같기때문에 그냥 name, hp, mp라고 하면 컴퓨터는 어떤 애를 말하는건지 구분 할 수가 없다. 그래서 우선적으로 ()안에 선언된 변수들을 우선해서 처리한다.(파란색 동그라미친 부분)

하지만 우리가 하고 싶은 건, 저 빨간 동그라미친 부분의 변수들에게 데이터를 넣어주는 것이다. 이때 this라는 키워드를 활용해 내가 지금 얘기하는 name, hp, mp는 class안에 정의한 변수(빨간동그라미 친 부분) 이라는 걸 알려준다.

 

더 간단하게

하지만 위 처럼 constructor를 작성하는 것도 뭔가 비효율적으로 보인다. 그냥 선언하고 바로 넣으면 좋을것 같다는 생각을 한 개발자들을 저 코드를 더 축약하기에 이르는데 아래와 같은 형태로 더 많이 활용한다. Flutter에서 일반적으로 아래와 같이 생성자를 작성하므로 위에 코드를 이해했다면 그걸 축약해서 아래처럼 쓰는 구나. 이해하고 넘어가자.

 

Human(this.name, this.hp, this.mp);

 

생성자를 통한 인스턴스의 생성

위의 코드는 class내에 생성자를 어떻게 사용해야하는 설계도를 작성하는 코드였다. 그러면 생상자를 활용해 인스턴스를 만들어보자.

인스턴스 만드는 방법은 매우 쉽다.

Human('주인공', 100, 200);

만들고자하는 인스턴스의 이름을 적고, ()안에 들어가야할 데이터들을 적어준다. 적는 순서나 구성은 class안에 정의해 두었으므로 거기에 따라서 적어주면 된다.

하지만 저렇게 인스턴스를 생성하면 코드내에서 인스턴스가 생성되기만 할뿐 활용하기 어려워진다. 그래서 변수를 만들어 데이터를 집어넣고 활용했던 것 처럼 인스턴스 역시 상자를 만들고 이름을 붙여 사용한다.

 

Human hero = Human('주인공', 100, 200);

// 이렇게 hero instance의 variable에 접근한다. 값을 확인해보고 싶다면 print문을 활용해 확인해봐라.
hero.name;
hero.hp;
hero.mp;

// 이렇게 hero instance의 method에 접근한다.
hero.attack();
hero.defence();

 

4. 인스턴스(instance)

위에서 부터 인스턴스 인스턴스 노래를 불러놓고 지금와서 또 다시 설명하자니 민망하다. class를 통해 만들어진 객체 하나하나를 instance라고 부른다.

 

이게 클래스의 끝이면 좋겠지만 끝이 아니다.

알아야할 것이 조금 더 남아있다. 다음 시간에는 상속, 접근제어자, 추상화, 캡슐화, 다형성 등의 심화된 class에 대한 내용을 다뤄봐야한다.

 

반응형

댓글