Flutter 창업반 2주차 TIL4 - 객체지향 프로그래밍
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디버깅 콘솔과 터미널의 기능차이 - 되는게 있고 안되는게 있고 겹쳐있음