반응형

이번 스터디에서는 static 키워드에 대해 알아보려 한다.

간단하게 Static키워드에 대해 말하자면,

인스턴스에 귀속되지 않고, 클래스 통째로 귀속이 되는것. 함수 또는 변수가 통째로 클래스에 귀속이 되는것을 말한다.

빠른 이해를 위해 소스 코드 확인 및 실행해보자.

간단한 직원이라는 클래스를 생성해보자.

조건은 아래와 같다.

1. 근무하고 있는 직원의 이름은 사람마다 다르다.

2. 직원들이 근무하는 건물은 동일하다.(한 건물)

class Employee{
  static String building;
  String name;
  
  Employee(
    String name,
  ):this.name = name;
  
  void printNameAndBuilding(){
    //static을 사용하였기 때문에, building에서는 this를 사용하지 않는다.(사용자체 불가)
    print('제 이름은 ${this.name}이고, ${building} 건물에서 근무 중 입니다.');
  }
  
}

building 변수에만 static을 사용한것을 볼수있다.

또한 printNameAndBuilding에 name앞에는 this를 붙였으나, building에는 붙이지 않은것을 볼수있다.

이는 하나의 인스턴스별로가 아닌, 클래스 자체에 귀속되기 때문이다.

바로 main함수에서 실행을 통해 자세히 알아보자.

void main() {
	Employee chulsoo = new Employee('철수');
    Employee youngHee = Employee('영희');
    
    chulsoo.printNameAndBuilding();
    youngHee.printNameAndBuilding();
}
제 이름은 철수이고, null 건물에서 근무 중 입니다.
제 이름은 영희이고, null 건물에서 근무 중 입니다.

최초 호출시엔 당연히 building값을 할당해 주지않았기 때문에 null값이 나온다.

이제 건물정보를 넣어줘야 하는데, 이때 인스턴스별로 지정해주는것이 아닌, 클래스자체에 직접접근하여 변경한다.

void main(){
	Employee.building = '여의도 공유오피스';
    chulsoo.printNameAndBuilding();
    youngHee.printNameAndBuilding();
}
제 이름은 철수이고, 여의도 공유오피스 건물에서 근무 중 입니다.
제 이름은 영희이고, 여의도 공유오피스 건물에서 근무 중 입니다.

건물정보의 변수값이 변경된 것을 확인할 수 있다.

Static keyword기 때문에, 위와 같이 클래스에 직접 접근하여 사용한다.

Static변수가 아닌 name은 기존처럼 "chulsoo.name="이런식으로 인스턴스별로 바꿔줘야 하지만

Static은 위와 다르게, 인스턴스 자체에 귀속되지 않고 클래스통째로 귀속되기 때문에

해당 클래스로 생성된 인스턴스의 모든 값이 변경된다.

 


void main(){
	Employee.building = '강남 공유오피스';
    chulsoo.printNameAndBuilding();
    youngHee.printNameAndBuilding();  
}
제 이름은 철수이고, 강남 공유오피스 건물에서 근무 중 입니다.
제 이름은 영희이고, 강남 공유오피스 건물에서 근무 중 입니다.

위와 같이 해도 마찬가지로 변경이된다.

아무리 많은 인스턴스를 생성한다 하더라도, static으로 선언된 변수는 클래스에 

직접 접근하여 한번만 변경해도 모든게 바뀐다.


만약 static을 사용하지 않았더라면 각각 인스턴스 별로 변경해줘야 했을것이다. (아래처럼)

"chulsoo.building = '영등포';"

"youngHee.building = '일산';"

......

이렇게 고정되는 값을 하나로 두면, for문같은 반복문을 가지고 인스턴스별로 설정해주는등의 일을 줄일수 있다.

따라서 이런경우엔 클래스 자체에 귀속시키는 static을 사용하는것이 좋다.

 

예제로 보니 이해하기 조금 더 빠른듯 싶다.

Static 스터디 끝.

반응형
반응형

이번 스터디에서는 메소드 오버라이딩에 대해 다뤄보려 한다.

다른말로 하면 "함수덮어쓰기" 정도로 표현할 수 있겠다.

바로 소스와 함께 알아보자.

class Parent {
  final int number;

  Parent(int number) : this.number = number;

  //Function 함수
  //Method
  int calculate() {
    return this.number * number;
  }
}

int형 상수 number값을 가지고, calculate 라는 기능을 가진 함수를 가진 클래스 하나를 선언한다.

※ 클래스 안에 선언된 것들을 보통 메소드라고 부르고, 클래스에 종속되지 않고,

밖에 별도로 선언된 것들을 함수라고 하는데 사실 이것도 분명히 나뉘는것은 아니다.

"메소드 = 함수" 동의어로 생각하면 되겠다.


다음은 위 Parent클래스를 상속받는 자식클래스 하나를 선언하자.

class Child extends Parent {
  Child(
    int number,
  ) : super(number = number);
  
  
  @override
  int calculate(){
    //부모클래스의 calculate함수를 자식클래스에서 덮어쓰기
    return this.number + this.number;

  }
}

여기서 알고 넘어가야 할것들

1. 해당 Child클래스는 Parent클래스를 상속받는다. 

2. @override는 decorator라 불리우며, 부모클래스의 함수를 재정의할때 표시한다.

3. 재정의하게 되면, 자식클래스의 calculate함수를 호출할때, 부모클래스의 함수가 아닌, 재정의된 함수를 호출한다.

4. 데코레이터를 생략해도 동작은한다. 하지만, 타인이 봤을때나 헷갈리지 않도록 표시하는것이 좋다.


본격적으로 main 함수에서 실행해보자.

void main(){
	Parent parent = new Parent(3);
    Child child = new Child(3);
    print(parent.calculate());
    print(child.calculate());
}
9
6

첫번째 print는 부모클래스의 calculate함수를 호출하기 때문에 9가 나온것이고, 

두번째 print는 자식클래스의 재정의된 calculate함수를 호출하기 때문에 6이 나온것이다.

만약, 자식클래스에서 재정의 하지 않았다면 부모클래스의 calculate를 호출하기 때문에 같은값이 9가 나왔을것이다.


이번에는 자식클래스에서 부모클래스의 함수를 직접 호출한 뒤 연산하는 기능을 넣어보자.

먼저 자식클래스의 calculate함수안에 아래와 같이 소스를 변경한다.

class Child extends Parent {
  Child(
    int number,
  ) : super(number = number);
  
  
  //decorator라 한다. 
  @override
  int calculate(){
    int result = super.calculate();

    return result + result;
  }
}

부모클래스의 calculate를 호출하기 위해선, super라는 키워드를 사용하여 호출할 수 있다는 점을 알수있다.

위 결과값은 result변수에 부모클래스의 calculate값을 호출하여 얻은 9에 한번더 9를 더해서 18이 나온다.

※상속을 받는 자식클래스에서는 부모클래스를 재정의하여 사용할 수 있고,

재정의 한다고 하여 부모클래스의 함수는 영향받지 않는다.

 

각자의 역할이 다른 클래스는 주축이 되는 클래스로 부터 상속을 받아 주요기능과 값을 사용하며,

기능에 따라 주요기능에 어떠한 값이나 기능을 더해서 사용해야 하는 경우들이 있다.

그럴때 주로 오버라이딩을 사용하면 좋을듯 싶다.

다시말해서, 현재온도를 계산해주는 클래스가 있다고 하자.

첫번째 자식클래스에서는 부모클래스로 부터 얻은 현재 온도에 한글 문장을 붙여서 안내해주는 기능이 있고,

두번째 자식클래스에서는 부모클래스로 부터 얻은 현재 온도에 영어 문장을 붙여서 안내해주는 기능이 있다고 하자.

 

그럼 자식클래스들에서는 부모클래스로 부터 온도만 받고, 해당 온도를 계산하는 함수를 재정의 한다음

문장을 붙여서 사용할 수도 있는것이다.

적절한 예가 되었을지 모르겠다....

 

오버라이딩 스터디 끝.

반응형
반응형

오늘 스터디한 부분은 '상속' 이라는 개념으로, 지난 스터디에 이어서 class스터디이다.

소스로 들어가기전에 '상속'이라는 단어를 먼저 알고가야 한다.


※상속이란 

1. 뒤를 이음.

2. 일정한 친족 관계가 있는 사람 사이에서, 한 사람이 사망한 후에 다른 사람에게 재산에 관한 권리와 의무의 일체를 이어 주거나, 다른 사람이 사망한 사람으로부터 그 권리와 의무의 일체를 이어받는 일.


위와 같이 정의되고 있다. 하지만 프로그래밍 언어에서의 상속이 위 사전적 내용과 백퍼센트 일치하진 않지만

어느정도의 내용을 가지고 가기 때문에, 반드시 기억하고 스터디를 시작할 필요는 있다.

먼저 상속이란것에 대해 알아보기 위해, class하나를 선언해보자.

void main(){

}

class Color {
  String name;
  String group;
  
  Color({
    String name,
    String group,
  }):this.name=name,
     this.group = group;
  
  void sayName(){
    print("이 색은 ${this.name}입니다.");
  }
  
  void sayGroup(){
    print("그룹은 ${this.group}입니다");
  }
  
}

생성자와 함수를 가지는 간단한 class하나를 준비한다.

다음으로, 상속을 알아보기 위해, class하나를 더 준비한다.

class Fruit extends Color{
   //1. Color클래스의 모든것을 상속받을수 있다.
  Fruit(
    String name,
    String group
  ):super ( // <- 2. 여기서 super는 부모 class를 지칭한다.
    name : name,
    group : group
  ); 
  //<- 3. 이 class가 생성될때, 받는 파라미터를 
  //부모color클래스에 name과group에 넣어준다는것.
  
  void sayCategory(){
    print("여름과일입니다");
  }
}

새로 만든 Fruit 클래스에서는 extends라는 용어를 사용하여 Color클래스를 상속받고 있다. (1번)

여기서 extends의 좌측에는 자식클래스명, 우측에는 부모클래스명을 작성하여 상속받는 클래스 형태를 만든다.

2번을 보면 기존에 this.name = name 형태로 작성되었지만, 지금은 super라고 지정하는 형태를 볼수있다.

여기서 super는 상속받은 부모클래스를 지칭하는 것이며, 해석하자면 Fruit클래스의 생성자에서 

생성당시 받는 파라미터를 부모클래스인 Color의 name과 group에 할당한다. 라는 의미이다.

main 함수에서 실행하여 알아보자.

void main(){
	//color클래스 선언
	Color color = new Color(name:'red',group:'A');
    
    //color클래스 정상동작 확인
    color.sayName();
    color.sayGroup();
    
    //자식클래스로 사용될 fruit클래스를 summer와 melon 파라미터를 넣어서 생성
    Fruit fr = new Fruit('SUMMER','MELON');
    
    //아래 결과를 실행
    print(fr.name);
    print(fr.group);
    
    
}
SUMMER
MELON

Fruit클래스가 생성될때, 받은 SUMMER와 MELON은 생성자를 통해 Color클래스의 name과 group으로 지정되면서

위와 같은 결과값이 나올수 있게되는것이다.

부모클래스로부터 상속을 받을때는 반드시 super키워드를 이용하여 부모클래스의 정보를 입력해주어야 하고

입력해주지 않으면 null값이 표현된다.

 

또한 Fruit클래스는 Color클래스를 상속받았기때문에 Color클래스에 있는 함수를 불러와서 사용할수 있다.

Fruit fr = new Fruit('SUMMER','MELON');
fr.sayName(); //color클래스에 있는 sayName()함수
이 색은 SUMMER입니다.

이렇듯 부모클래스를 상속받아서 정의된 자식클래스는 반드시 생성자를 통해 부모클래스의 정보를 할당하고,

부모클래스의 함수를 그대로 받아서 사용할수 있다는것을 확인하였다.

여기서 중요한 참고사항으로, 자식은 부모클래스를 상속받으면 부모클래스가 가지고 있는 함수와 변수를 

사용할 수 있지만, 반대로 부모클래스는 자식클래스의 변수나 함수를 사용할 수 없다. (중요)

또한, 하나의 부모클래스는 여러개의 자식클래스를 가질수 있으나, 자식클래스는 하나의 부모클래스만 가질수 있다.

 

과연 어디서 이 기능을 사용하는가...? 있어서 좋은점은...? 이런 의문은 곧 다룰 여러예제들을 통해 파악하겠다.

상속 스터디 끝.

반응형
반응형

지난 스터디에서 class와 constructor를 알아보았다.

이번 스터디에서는 Getter와 Setter라는 것에 대해 알아보려 한다.

실습을 진행하기 전에, 간단한 기능을 가지는 class를 하나 선언하여 준비한다.

void main() { 
  
  Color color = new Color(
    name: 'red',
    group : 'A'
  );
  
  color.sayName();
  
}


class Color {
  String name;
  String group;
  
  
  //네임드 파라미터를 사용하는 생성자 하나 선언
  //중괄호의 유무
  Color({
    String name,
    String group
  }) : this.name = name,
       this.group = group;
    
  void sayName(){
    print('이 색은 ${this.name}입니다.');
  }
}

이 색은 red입니다.

 

Getter와 Setter를 알기전에 먼저 Private변수에 대해 알아야 하는데, 일단 선언하는 방법은

변수명에 _언더바를 붙여주면 된다.

class Color {
	String name;  -> String _name;
	String group; -> String _group;	
}

언더바를 붙이면 Private 변수로 사용된다. 보통 JAVA에서는 Private변수의 경우 소속된 class에서만 

사용이 가능하지만, Dart의 경우 같은 파일내에 존재하는 영역에서는 어디서나 가져와서 사용이 가능하다.

그럼 변경된 Private변수명에 맞게 class내부를 수정 후, 출력해보자.


void main(){
  Color color = new Color(
    name: 'red',
    group : 'A'
  );
  
  print(color._name);
  
  
}


class Color {
	String _name;
    String _group;
    
  	Color({
	    String name,
	    String group
  	}) : this._name = name,
	       this._group = group;
	    
  	void sayName(){
	    print('이 색은 ${this._name}입니다.');
  	}            
}
red

main 함수의 print함수를 보면 color클래스의 _name을 호출하고 있다. 

_name은 color클래스의 프라이빗 변수로 선언되어 있음에도 불구하고, 같은 파일내에 있기때문에

Dart의 특성상 사용할 수 있는것이다.

만약 위 소스에서 main 함수와 class가 다른 파일에 있었다면 에러가 발생했을 것이다.


그럼 다른 파일에 선언되어 있는 경우엔 어떻게 불러와서 사용할 수 있을까?

이때를 위해 바로 Getter와 Setter가 존재하는 것이다.

선언은 class안에 아래와 같이 한다.

class Color {
	String _name;
	String _group;
   
	Color({
	    String name,
		String group
  	}) : this._name = name,
	       this._group = group;
	    
	void sayName(){
		print('이 색은 ${this._name}입니다.');
	}  
  
	get name{
		return this._name;
	}
  
	set name(String name){
		this._name = name;
	}
}

getter는 get 이름 형태로 선언하며, 보통 private변수명에서 언더바를 제거한 이름을 사용한다.

setter또한 set이름 형태로 선언하며, 값을 지정하는 역할을 하기 때문에 파라미터를 받게된다.(타입은 원하는 대로)

getter의 경우 호출하면 class의 private변수의 값을 리턴하도록 하고 있으며, setter의 경우 받은 파라미터를

class에 할당하는 역할을 하고 있다.

한번 호출해 보자.


void main(){
	Color color = new Color(
		name: 'red',
		group : 'A'
	);
  
	print(color._name);
  
  
	print(color.name);
  
	color.name = 'blue';
	print(color.name);
  
}


class Color {
	String _name;
	String _group;
   
	Color({
		String name,
		String group
	}) : this._name = name,
	       this._group = group;
	    
	void sayName(){
		print('이 색은 ${this._name}입니다.');
	}  
  
	get name{
		return this._name;
	}
  
	set name(String name){
		this._name = name;
	}
}
red
red
blue

main 함수 내 정의된 첫번째 print의 경우, 같은 파일내 private함수가 있기 때문에 바로 호출하여

사용할수 있다는 것을 보여준 예시이고,

 

두번째 print는 getter를 이용하여 class안에 포함된 _name값을 리턴받아 출력하는 예시이다.

마지막 세번째는 setter를 이용하여, blue라는 값을 set후, getter를 이용하여 출력한 예시이다.


번외로 , 여기서 하나 드는 의문점.

아래와 같이 선언해서 써도 상관없는거 아닌가?

  void getName(){
    return this._name;
  }
  
  void setName(String name){
    this._group = name;
  }

상관없지만, 단순히 보면 소괄호의 사용유무 정도라고 할수 있는데, 때에 따라 get(ter) set(ter)로 간단하게 

사용할 때가 있다. 언제 getter와 setter를 사용하는게 좋을지, 함수로 만들어서 사용해서 좋을지는 

실제 프로그램을 만들다 보면 구분지어 쓸때가 있다.

오늘의 스터디 Getter와 Setter 끝.

반응형

+ Recent posts