OOP (객체 지향 프로그래밍)

class변수, 함수

Instance를 만들 수 있음.


void main(){
  Idol blackPink = Idol('블랙핑크',  ['1','2','3','4','5']);

  Idol blackPink2 = Idol('블랙핑크',  ['1','2','3','4','5']);

  // blackpink, 2 랑은 다름.
  //그런데 const로 만들면 두개가 같아짐.
  //같은 인스턴스로 만들어짐.


  print(blackPink.name);
  print(blackPink.members);
  blackPink.sayHello();
  blackPink.introduce();


  Idol bts = Idol(
    'BTS',
    ['RM', '진', '...'];
  )

  Idol bts = Idol.fromList([
    ['RM', '진', '...'],
    'BTS',
  ]);

}


/**
 * Idol class
 name (이름) - 변수
 members(멤버들) - 변수
 sayHello (인사) - 함수
 introduce (멤버소개) - 함수

 constructor(생성자) 
 */
class Idol {
  String name = '블랙핑크';
  List<String> members = ['지수', '제니', '리사', '로제'];
  
  //Idol(String name, List<String> members)
  //: this.name = name,
  //  this.members = members;

  // 위와 동일하다.
  //Idol(this.name, this.members);

  // 이런식으로도 constructor를 구현할 수 있다.
  Idol.fromList(List values)
  : this.members = values[0],
    this.name = values[1];

  void SayHello(){
    print('안녕하세요 ${this.name} 입니다.');
  }

  void introduce(){
    print('저희는 ${this.members}  있습니다.');
  }

뭐 이렇게 쓸수 있다. 값을 바꾸지 못하게 하기 위해

  final String name;
  final List<String> members;

이렇게 대부분의 class 안에는 final로 선언해준다.

constructor 앞에는 const를 입혀준다.

class getter, setter

// getter/ setter 
// 데이터 가져올 때, 데이터 설정할 때,
class Idol {
  String name = '블랙핑크';
  List<String> members = ['지수', '제니', '리사', '로제'];
  
  Idol(this.name, this.members);

  Idol.fromList(List values)
  : this.members = values[0],
    this.name = values[1];

  void sayHello(){
    print('안녕하세요 ${this.name} 입니다.');
  }

  void introduce(){
    print('저희는 ${this.members}  있습니다.');
  }

  // getter
  String get firstMember{
    return this.members[0]
  }

  set firstMember(String name){
    this.members[0] = name;
  }
}

void main() {
  Idol blackPink = Idol ('블랙핑크' , ['','','','','',]);

  Idol bts = Idol ('BTS' , ['','','','','',]);

  print(blackPink.firstMember);
  print(bts.firstMember);

  // 이렇게 하면 setter 를 부름
  blackPink.firstMember = '우하하';

  // setter 의 변수 Stirng name에 우하하를 가져옴.
}
  1. 왜 getter 를 사용하냐 그냥 함수 만들어서 하면 되지. 사실상 기능적인 차이는 없다. getter는 간단하게 가공할 때 사용한다고 보면 됨. 함수는 로직이 많이 들어가는 때에 사용한다.

뭐 근데 막 써도 됨.

  1. final 지정하면 setter를 못쓰는거 아니냐 그래서 사실상 현대 프로그래밍에서 굉장히 안쓰는 기술임.

Private 변수

파일 밖에서 외부에서 사용하는 변수

변수 앞에 _ 를 붙여주면 됨.

상속

상속 - inheritance

상속을 받으면 부모 클래스의 모든 속성을 자식 클래스가 부여받는다.

class Idol {
  //이름
  String name;
  int memberCount;

  Idol({
    required this.name;
    required this.memberCount;
  })

  void sayName() {
    print('저는 ${this.name} 입니다.');
  }

  void sayMemberCount() {
    print('${this.name}${this.memebercount} 명 입니다.');
  }
}

class BoyGroup extends Idol{
  BoyGroup(String name, int memebercount)
  : super(
      name: name,
      memberCount: memberCount
    );
  
  void sayMail(){
    print('저는 남자 아이돌입니다.');
  }
}

class GirlGroup extends Idol {
  GirlGroup(
    String name,
    int memberCount,
  ) : super(
    name: name,
    memberCount : memberCount,
  );

  void sayFemale(){
    print('저는 여자아이돌입니다.');
  }
}

void main(){
  Idol apink = Idol(name : '에이핑크', memberCount : 5);

  apink.sayName();
  apink.sayMemberCount();


  // 이렇게 상속받아서 사용할 수 있다,
  BoyGroup bts = BoyGroup('BTS', 7);

  bts.sayMemberCount();
  bts.sayName();
  bts.sayMail();
  // apink.sayMail()은 사용할 수 없음 (위로 올라갈 수 없음)

  GirlGroup redvelbet = GirlGroup('Red Velvet', 5);

  redvelbet.sayMemberCount();
  redvelbet.sayName();
  redvelbet.sayFemale(); // apink, bts에서는 sayFemale()을 사용할 수없음

  // 타입은 부모의 타입을 가져간다.
  print(apink is Idol); // true
  print(apink is BoyGroup); // false
  print(apink is GirlGroup); // false

  print(bts is Idol); // true
  print(bts is BoyGroup); // true
  print(bts is GirlGroup); // false

  print(redvelbet is Idol); // true
  print(redvelbet is BoyGroup); // false
  print(redvelbet is GirlGroup); // true
}

주의 할 점은 super 안에서 변수 넣어줘야하는 부분

또 자식 - 부모로 갈 수 없음 자식 - 자식으로도 갈 수 없음

메소드 오버라이딩

메소드 : 클래스 안에 있는 함수 override - 덮어쓰다.

class TimesTwo {
  final int number;

  TimesTwo(this.number,);

  //method
  int calculate(){
    return number * 2;
  }

}

class TimesFour extends TimesTwo {
  final int number;

  TimesFour(int number) : super(number);

  //method
  @override
  int calculate(){
    return super.calculate() * 2;
  }

}

void main(){
  TimesTwo tt = TimesTwo(2);

  print(tt.calculate()); // 4

  TimesFour tf = TimesFour(2);

  print(tf.calculate());
}

이런식으로 overriding 할 수 있다.

Static

class Employee{
  // static은 insatance에 귀속되지 않고 class에 귀속된다.
  // 알바생이 일하고 있는 건물
  static String? building;

  // 알바생 이름
  final String name;

  Employee(this.name);

  void printNameAndBuilding(){
    print('제 이름은 $name 입니다. $building 건물에서 근무하고 있습니다.');
  }

  static void printBuilding(){
    print('저는 $building 건물에서 근무중입니다.');
  }
}


void main(){
  Employee seulgi = Employee('슬기');
  Employee chorong = Employee('초롱');

  seulgi.name = '코드팩토리';
  seulgi.printNameAndBuilding(); // 이름은 다르게 나옴
  chorong.printNameAndBuilding(); // 이름은 다르게 나옴
  // 건물명은 null로 동일하게 나옴.

  Employee.building = '오투타워'; 
  // 클래스 값으로 넣을 수 있따.

  seulgi.printNameAndBuilding(); // 빌딩 값은 똑같이 나옴
  chorong.printNameAndBuilding(); //빌딩 값은 똑같이 나옴

  Employee.printBuilding(); // 그냥 클래스로 호출할 수 있음.
}

자 이런식으로 static 키워드를 사용할 수 있다.

Interface

void main(){

}

// Interface
abstract class IdolInterface{ // 추상적으로 만들면 이걸로 인스턴스 만들지 못하게 막을 수 있음.
  String name;

  IdolInterface(this.name);

  void sayName() // 함수의 바디 없어도 됨.
}

class BoyGroup implements IdolInterface{
  String name;

  BoyGroup(this.name);

  void sayName(){
    print('제이름은 $name 입니다.');
  }
}
// 위와 같이 설정 안해두면 에러 남.

class GirlGroup implements IdolInterface{
  String name;

  GirlGroup(this.name);

  void sayName(){
    print('제이름은 $name 입니다.');
  }
}

void main(){
  BoyGroup bts = BoyGroup('BTS');
  GirlGroup apink = GirlGroup('apink');

  bts.sayName();
  apink.sayName();

  print(bts is IdolInterface); // true
  print(bts is BoyGroup); // true
}

interface라는 애는 class의 형태를 만들어두는 거라고 보면 됨.

## generic

 class Lecture<T>{
  final T id; // id 값의 type을 동적으로 지정할 수 있음
  final String name;

  Lecture(this.id, this.name);

  void printIdType(){
    print(id.runtimeType);
  }
 }

 void main(){
  Lecture<String> lecture1 = Lecture('123', 'lecture1');

  lecture1.printIdType(); // String

  Lecture<int> lecture1 = Lecture(123, 'lecture2');

  lecture2.printIdType(); // Int
 }

타입을 외부에서 받을 때

## oop에 대하여…

 void main(){
  Test test = Test();

  
 }

 class Test

이렇게만 해도 Test는 Object를 상속을 하고 있다. 그러므로 Object안의 메서드들을 사용할 수 있다. 그래서 우리는 oop라고 부른다.

이게 끝