공부 일기/TIL

Flutter 창업반 2주차 TIL4 - 객체지향 프로그래밍

oosuhada 2024. 11. 1. 09:48

 

10/31 목 - 객체지향 프로그래밍 (프로그래밍의 핵심)

 

클래스 - 객체 : 붕어빵 틀 - 붕어빵 

/ 객체-실제 데이터 (Object) 의 구조와 동작을 정의하는 틀

/ class [클래스 이름-대문자로 시작] { … }

/ 속성 + 메서드를 하나로 묶은 개념

/ 속성, 메서드는 클래스 안에 있는 요소라서 클래스의 멤버라고도 부름

 

1. 속성 (Attribute) 은 작업 수행할때 -  인스턴스 변수 (Instance Variable), 지역 변수 (Local Variable), 정적 변수 (Static Variable)가 있다.

 

1) 인스턴스 변수 (Instance Variable) - 흔히 생각하는 변수. this를 통해 접근할 수 있다.

/ this를 사용해 메서드에 속한 변수와 인스턴스 변수를 구분 가능

class Person { 

String name = '강미래'; 

int age = 25; 

void changeName(String name) {

 this.name = name; } 

}

위 코드의 this.name = name; 에서 this.name 은 인스턴스 변수 인 name , name 은 매개변수 인 same 을 가리킴 참고로, this 가 붙지 않은 변수는 더 가까이 있는 변수로 우선 취급 - this는 웬만하면 사용하지 않는것이 좋음

/ 인스턴스 변수는 클래스의 모든 곳에서 접근 가능

/ 객체가 존재하는 동안(생명주기) 계속 메모리상에 존재

/동일한 클래스 로 생성한 객체 들은 각 객체 들은 값을 공유하지 않고, 개별적인 값

/ 객체는 . 을 통해 클래스 에 정의되어 있는 속성메서드 를 사용

/ final을 사용해서 객체 를 통해서 변수 의 값을 바꾸는 것을 막을 수 있음

 

class Person {

  String name = '';

int age = 0;

}

 

void main() {

Person paul = Person();

paul.name = 'Paul';

paul.age = 25;

 

  Person mark = Person();

  mark.name = 'Mark';

  mark.age = 30;

  

  paul.age = 27;

  print(paul.age); // 27

  print(mark.age); // 30

}

————————————————

class Person {

  final String name = '강미래';

int age = 25;

}

 

void main() {

Person paul = Person();

paul.name = 'Paul'; // 오류 발생

  paul.age = 30;

}

 

 

2) 지역 변수 (Local Variable) - 특정 코드 블룩 안에 선언된 변수

class Person {

String name = '강미래';

 

void sayName() {

String nameSentence = '내 이름은 $name !';

print(nameSentence);

}

}

위 코드에서 sayName() 안의 nameSentence는 sayName안에서만 사용 가능한 지역 변수.  name 은 지역 변수 가 아니라 인스턴스 변수

 

class Person {

String name = '강미래';

 

void sayName() {

String nameSentence = '내 이름은 $name !';

print(nameSentence);

}

 

void sayNameAgain() {

print(nameSentence); // 오류 발생

}

}

위 코드에서 nameSentence 는 sayName() 안에서만 사용할 수 있는 지역 변수기 때문에 sayName() 의 코드 블록 밖에서는 오류. 

/ 변수 가 선언된 코드 블록의 실행이 끝나면 메모리 상에서 사라짐. 생명 주기가 짧다.

nameSentence 는  sayName() 실행이 사라지면 없어진다.

 

3) 정적 변수 (Static Variable) - 클래스 변수. 객체(클래스를 가지고 만든 실제 데이터)에 종속되지 않고 클래스 자체에 종속하는 변수

 

class Circle {

  static double pi = 3.14159;

  double radius = 0;

}

 

void main() {

print(Circle.pi); // 3.14159

print(Circle.radius); // Error: Member not found: 'radius'.

}

 

/ pi 의 맨 앞에 static - static으로 선언한 변수는 정적 변수

/ radius 는 인스턴스 변수

/ 정적 변수 pi는 클래스 이름 Circle으로 접근 가능, radius는 인스턴스 변수여서(Circle안에서 선언된게 아님) 클래스 이름으로 접근할 수 없음 -> 그럼 어떻게?

/인스턴스 변수 radius는 객체를 통해 접근해야 한다. 

void main() {

print(Circle.pi); // 3.14159

        Circle circle = Circle ();

print(Circle.radius); 

/ 정적 변수는 객체를 뜻하는 this를 통해 접근할 수 없다

void printpi() {

   print(this.pi) // 오류 발생

   print(pi)는 가능

 

/객체 마다 개별적인 값을 갖지 않고, 모든 객체 가 서로 값을 공유??

class Circle {

  static double pi = 3.14159;

  

  void printPi() {

    print(pi);

  }

}

 

void main() {

  Circle circle1 = Circle();

  circle1.printPi(); // 3.14159

  

  Circle circle2 = Circle();

  circle2.printPi(); // 3.14159

  

  Circle.pi = 3.14;

  circle1.printPi(); // 3.14

  circle2.printPi(); // 3.14

}

/circle1 과 circle2 는 독립적인 객체이지만 pi 정적변수이기 때문에 Circle로 만든 모든 객체에 접근한것 

/영향력이 크기 때문에 함부러 static으로 바꿔주면 안되고 최대한 인스턴스 변수를 사용할 것

 

지역 변수 (Local Variable)or 로컬변수, 정적 변수 (Static Variable)


인스턴스 변수 로컬/지역 변수
사용 가능 범위 클래스 내의 모든 범위 해당 코드 블록 내의 모든 범위
생명 주기 객체가 존재하는 동안
(객체가 소멸할 때까지)
해당 코드 블록이 실행되는 동안

인스턴스 변수 정적 변수

클래스 종속 객체 종속
키워드
static 붙어야
접근 방법 객체이름을 통해 접근 클래스 이름을 통해 접근
객체끼리 값을 공유하는지 ? X O

 

2. 메서드 (Method) 객체동작 을 정의하는 함수. 속성 을 변경하거나 객체 를 가지고 특정 작업을 수행.

 

/ cf. 메서드 - 클래스 내부에 존재하는 영역으로 특정 기능 수행하기 위한 코드

함수 중에서 클래스 내부에 정의한 함수를 메소드라고 부르는 것

함수는 클래스 의존x 독립적으로 존재하고, 

메소드는 class 및 객체에 종속적. 의존이다.

  • 함수는 객체가 필요하지 않고 독립적인 반면, 방법은 객체와 연결된 함수입니다.
  • 함수를 개체 이름으로 직접 호출할 수 있지만 메서드는 개체 이름으로 호출할 수 있습니다.
  • 함수는 데이터를 전달하거나 반환하는 데 사용되며 메소드는 클래스에서 데이터를 작동합니다.
  • 함수는 독립적인 기능인 반면, 방법은 객체 지향 프로그래밍 아래 있습니다.
  • 함수에서는 클래스를 선언할 필요가 없지만 메서드를 사용하려면 클래스를 선언해야 합니다.
  • 함수는 제공된 데이터에서만 작동할 수 있는 반면 메소드는 지정된 클래스에서 제공된 모든 데이터에 액세스할 수 있습니다.

 

1) 인스턴스 메서드 (Instance Method) - 객체 에 속해 있는 메서드

 

class Person {

  String name = '강미래';

int age = 25;

 

  void introduce() {

    print('안녕 ? 나는 $age살 $name !');

  }

}

// 클래스 내부 객체에 속한  introduce() 가 인스턴스 메서드

/ this를 통해 접근 가능

/ 인스턴스 변수와 마찬가지로 클래스의 모든곳에서 접근할 수 있음

 

2) 정적 메서드 (Static Method) or 클래스 메서드 - 객체 에 종속되지 않고, 클래스 자체에 속하는 메서드

// 객체 에 종속되지 않고, 클래스 자체에 속하는 메서드

/ 클래스 이름을 통해 호출 

 

class Circle {

static double pi = 3.14159;

double radius = 0;

 

  static void printPi() {

  print(pi);

  }

  

  void printRadius() {

    print(radius);

  }

}

 

void main() {

Circle circle = Circle();

circle.radius = 5;

circle.printRadius(); // 5

circle.printPi(); // 오류 발생

}

위 코드에서 printRadius는 인스턴스 메서드이기 때문에 Circle클래스 - Circle.printRadius를 통해 호출할 수 없음. 반드시 Circle circle = Cricle() 이라고 객체를 통해 circle.printRadius로 호출할 수 있음

(대문자와 소문자 차이 중요함)

/this를 통해 호출할 수 없음

/*코드블록에서 인스턴스 변수를 사용할 수 없음

 

class Circle {

double pi = 3.14159;

double radius = 0;

 

  static void printPi() {

  print(pi); // 오류 발생

  }

}

위 코드에서 printPi가 정적 메서드이기 때문에 정적 변수만 사용할 수 있음!!

static double pi = 3.14159;로 정적 변수로 만들어줘야 오류 발생하지 않음

반대로 인스턴스 메서드에서는 정적 변수 사용 가능

/클래스에 종속되어 있기 때문에 객체마다 개별적으로 동작하지 않고 모두 동일하게 동작함

 

3. 생성자 (Constructor)

/객체를 생성하고 초기화하기 위해 사용하는 특수한 메서드

/ 클래스 와 생성자 이름이 같다.

/반환값 이 없기 때문에 void 타입이다

/클래스 를 통해 객체 가 생성될 때 자동으로 호출

 

class Person {

  String name;

int age;

 

  Person(this.name, this.age);

}

 

void main() {

  Person paul = Person('Paul', 25);

  Person mark = Person('Mark', 30);

}

/생성할 수 있는 객체 의 수에는 제한이 없음 — 메모리가 허용하는 한 무한정

 

class Person {

  String name;

int age;

 

  Person(this.name, this.age);

}

 

void main() {

Person paul1 = Person('Paul', 25);

Person paul2 = Person('Paul', 25);

print(paul1 == paul2); // false

}

/생성한 객체 들은 서로 같지 않은 독립된 개체 - 이름 숫자가 같더라도

/하나의 클래스로 여러 객체를 생성할 수 있기 때문에 재사용성 높은 코드 가능

/개발자는 효율성을 중시 - 한번 쓴 코드를 다시 쓰지 않도록 끊임없이 고민함

 

1) 기본 생성자 (Default Constructor) - 매개변수를 갖지 않는 생성자

 

class Car {

  Car();

}

 

/[클래스 이름](); - Car() 이 Car 클래스의 기본 생성자

/자동으로 정의되기 때문에 클래스 에 class Car { Car(); } 이라고 따로 명시하지 않아도 됨

/new.라는 키워드를 사용해서 생성할수도 있지만 굳이

/인스턴스 변수 들이 모두 초기화되어 있는 상태여야 / 초기값이 있어야

 

class Car {

String name = '';

List<String> models = [];

  

  Car();

}

위 코드에는 초기값이 ‘’, []로 있지만 아래 코드에는 String, List 둘다 non-nullable하기 때문에 초기값이 없다

 

class Car {

String name; // Error: Field 'name' should be initialized because its type 'String' doesn't allow null.

List<String> models; // Error: Field 'models' should be initialized because its type 'List<String>' doesn't allow null.

  

  Car();

}

 

2) 매개변수 생성자 (Parameterized Constructor) - 매개변수가 있는 생성자. 매개변수를 통해 외부에서 인스턴스 변수들의 초기값을 설정

 

class Car {

String name;

List<String> models;

  

  Car(this.name, this.models);

}

/Case1. [클래스 이름](this.변수); 매개변수 생성자 Car(this.name, this.models)를 통해 받아온 this.name 과 this.models 가 Car 의 변수인 name 과 models 에 대입

 

class Car {

  String name;

  List<String> models;

 

  Car(String name, List<String> models)

      : this.name = name,

        this.models = models;

}

/Case2. [클래스 이름]([타입] [매개변수 이름]) : this.변수; 

Car(String name, List<String> models)안에서 this. 를 통해 받아온 name 과 models 가 Car 의 변수인 name 과 models 에 각각 대입

 

class Car {

  String name = '';

  List<String> models = [];

 

  Car(String name, List<String> models) {

    this.name = name;

    this.models = models;

  }

}

/Case3. [클래스 이름]([타입] [매개변수 이름]) { this.변수; }

/매개변수 생성자는 객체 생성할 때 매개변수 를 넣지 않으면 오류가 난다. 

 

class Car {

String name;

List<String> models;

  

  Car(this.name, this.models);

}. // Car이라는 클래스를 만듬

 

void main() {

Car car = Car(‘BMW’, [‘M1’, ‘M2’, ‘M3’]); //car 이라는 객체 생성

        Car.printModels( )

} 

 

3) 네임드 생성자 (Named Constructor) - 클래스 메서드 와 같은 형식으로 클래스 이름을 통해 호출하는 생성자

 

class Car {

  String name;

  List<String> models;

 

  Car.fromList(List values)

      : this.name = values[0],

        this.models = values[1];

}

 

/[클래스 이름].[메서드 이름]([타입] [매개변수 이름]) : this.변수; - Car.fromList(List values) 에 있는 values 의 첫번째 요소는 Car 의 인스턴스 변수인 name 에, values 의 두번째 요소는 Car 의 인스턴스 변수인 models 에 대입

/선언하는 방식이지만 직관적인 방법은 아님

/ 클래스 에 있는 변수타입 이 맞지 않는 값을 넣으면 오류가 난다

 

 

제네릭 클래스 (vs제네릭 함수) - 꽤 중요

/List<>, Set<>, Map<> 모두 <>가 제네릭을 의미하는 꺽쇠.

/[클래스 이름]<타입 파라미터>

/제네릭 함수와 마찬가지로 특정 타입에 의존하지 않고, 여러 타입에 대해 동일한 코드를 적용할 수 있어서 재사용성 높은 코드를 짤 수 있음

 

ex1. 제네릭 클래스 없이

 

class IntBox {

int value;

 

IntBox(this.value);

 

int getValue() {

return value;

}

}

 

class StringBox {

String value;

 

StringBox(this.value);

 

String getValue() {

return value;

}

}

 

void main() {

  var intBox = IntBox(10);

  print(intBox.getValue()); // 10

 

  var stringBox = StringBox('Hello');

  print(stringBox.getValue()); // Hello

}

 

ex2. 제네릭 클래스 사용

class Box<T> {

  T value;

 

  Box(this.value);

 

  T getValue() {

    return value;

  }

}

 

void main() {

  var intBox = Box<int>(10);

  print(intBox.getValue()); // 10

 

  var stringBox = Box<String>('Hello');

  print(stringBox.getValue()); // Hello

}

 

 

상속 (Inheritance) - 기존 클래스의 기능을 확장하여 새로운 클래스 생성

/하나의 클래스 가 다른 클래스속성메서드 를 물려받음

/물려주는 클래스부모 클래스 (Parent Class, Superclass),

물려받는 클래스자식 클래스 (Child Class, Subclass)

 

class Person {

String name = '';

 

  void eat() {

    print('냠냠 !');

  }

}

 

class Student extends Person {

  void study() {

    print('열공 !');

  }

}

 

void main() {

  Student student = Student();

  student.name = '강미래';

  student.eat(); // 냠냠 !

  student.study(); // 열공 !

}

/class [자식 클래스 이름] extends [부모 클래스 이름] { … } - 부모 클래스 를 확장한다는 의미에서 extends 라는 키워드를 사용. Person 은 부모 클래스, Student 는 자식 클래스

/부모 클래스자식 클래스 에게 자신의 모든 속성메서드상속. 

/Student 에는 name 이랑 eat()정의 안되었지만, 상속받아 사용할 수 있음

/부모 클래스자식 클래스 에 있는 멤버 (속성, 메서드) 를 사용할 수 없음

/부모 클래스자식 클래스 에 있는 멤버 (속성, 메서드) 를 사용할 수 있음

this가 객체를 가리키는 것처럼 super가 부모클래스를 가리킴

/자식 클래스상속 받은 속성메서드재정의 (Overriding) 하거나 기능을 확장할 수 있음

 

*현대적인 프로그래밍 기법 - 함수형 프로그래밍, 비동기형 프로그래밍, 객체 지향 프로그래밍

 

얘기한 부분들 트러블 슈팅 - dart pad, vs코드에서 안됐던 부분

커밋 우선 해두고 분리하는 부분 커밋하기

보통 한 파일에 한 클래스, 강하게 붙어있어야 할 필요가 없다면 다른 파일로 분리

커밋 컨벤션이란?

Readme.md 파일 작성법

Vs code디버깅 콘솔과 터미널의 기능차이 - 되는게 있고 안되는게 있고 겹쳐있음