🎯 오늘은 1강 남은 객체 지향 프로그램을 마저 듣고, 개인 과제를 시작했다.
우선, 기반 작업을 진행했고, 오류가 생기면 여기저기 고쳐도 보고, 바꾸기도 하면서 하나씩 해결했다.
✅ 기존 클래스의 기능을 확장하여 새로운 클래스를 만드는 것
✅ 하나의 클래스가 다른 클래스의 속성 과 메서드 를 물려받는 것으로, 물려주는 클래스는 부모 클래스(Parent Class, Superclass), 물려받는 클래스는 자식 클래스(Child Class, Subclass)라고 부른다.
📋
class [자식 클래스 이름] extends [부모 클래스 이름] { … }class Person { void eat() { print('냠냠 !'); } } // class Student extends Person { void study() { print('열공 !'); } }
🔍
부모 클래스는 자식 클래스에게 자신의 모든 속성과 메서드를 상속한다.class Person { String name = ''; // void eat() { print('냠냠 !'); } } // class Student extends Person { void study() { print('열공 !'); } } // void main() { Student student = Student(); student.name = 'Mini'; student.eat(); // 냠냠 ! student.study(); // 열공 ! }✔
Student에는name이랑eat()이 정의되어 있지 않아도 사용할 수 있다.
🔍
부모 클래스는 자식 클래스에 있는 속성, 메서드를 사용할 수 없다.class Person { void eat() { print('냠냠 !'); } } // class Student extends Person { void study() { print('열공 !'); } } // void main() { Person person = Person(); person.study(); // Error: The method 'study' isn't defined for the class 'Person'. }
🔍
super를 통해 자식 클래스가 부모 클래스의 속성과 메서드를 사용할 수 있다.class Person { String name = 'Mini'; // void eat() { print('냠냠 !'); } } // class Student extends Person { void eatAndIntroduce() { super.eat(); print('맛있게 먹는 ${super.name}'); } } // void main() { Student student = Student(); student.eatAndIntroduce(); } /* 냠냠 ! 맛있게 먹는 Mini */✔
super는 부모 클래스를 가리키며,super.eat();을 하면Person에 있는eat()이 호출되고,super.name을 하면Person에 있는 인스턴스 변수인name이 들어간다.
🔍
자식 클래스 는 상속 받은 속성 과 메서드 를 재정의 하거나 기능을 확장할 수 있다
✅ 재정의(Overriding)
✔ 자식 클래스가 부모 클래스로부터 상속 받은 속성과 메서드를 그대로 사용하지 않고, 덮어 씌우는 것을 의미한다.
✔ 부모 클래스에 정의되어 있는 속성이나 메서드가 마음에 안 들어서 새로 정의하고 싶을 때 사용한다.
📋
@override [변수 이름] = [값];class Person { String name = 'Mini'; // void eat() { print('냠냠 !'); } } // class Student extends Person { String name = '여러분'; // void study() { print('열공하는 $name !'); } } // void main() { Student student = Student(); student.study(); // 열공하는 여러분 ! }✔
Student 의name은Person의name을 재정의한 속성이다.
📋
@override [반환 타입] [함수 이름]() { … }class Person { void eat() { print('냠냠 !'); } } // class Student extends Person { void eat() { print('쩝쩝 !'); } } // void main() { Student student = Student(); student.eat(); // 쩝쩝 ! }✔
Person의eat()을Student에서 재정의했다.
class Person { void eat() { print('냠냠 !'); } } // class Student extends Person { void eat() { super.eat(); print('쩝쩝 !'); } } // void main() { Student student = Student(); student.eat(); } /* 냠냠 ! 쩝쩝 ! */✔
super를 통해 기존에 정의되어 있던 메서드를 호출한 후에 재정의하면 된다.
💡 공통적인 속성과 메서드를 부모 클래스에 정의하고, 공통되지 않는 요소들만 따로 자식 클래스에 정의해서 중복된 코드를 줄이고, 코드의 재사용성을 높일 수 있다.
❌ 상속 허용
📋final class [클래스 이름] { … }final class Person { void eat() { print('냠냠 !'); } } // class Student extends Person { // Error: The type 'Student' must be 'base', 'final' or 'sealed' because the supertype 'Person' is 'final'. }👉 하나의 클래스로부터 자식 클래스를 만들 수 없도록 하는 것으로, 상속 받을 수 없도록 만든다.
✅ 객체 (Object) 들을 사용하여 프로그램을 구성하는 방식
📕 클래스를 통해 틀을 정의해두고, 여러 객체를 만들기 때문에 효율적이다.
📒 클래스를 상속 받아서 기능을 확장할 수 있기 때문에 코드를 재사용할 수 있다.
📗 클래스를 통해 만든 객체들이 각각 독립적으로 동작하기 때문에 특정 객체를 수정해도 부작용이 생길 일이 적다.
💻 예제
class Car { String name; List<String> models; // Car(this.name, this.models); // void introduceName() { print('안녕하세요, 저희는 $name 입니다 !'); } // void introduceModels() { print('저희는 $models 이렇게 ${models.length}가지 모델을 가지고 있습니다 !'); } } // void main() { Car bmw = Car('BMW', ['320i', '340i', 'M3']); print(bmw.name); // BMW print(bmw.models); // [320i, 340i, M3] bmw.introduceName(); // 안녕하세요, 저희는 BMW 입니다 ! bmw.introduceModels(); // 저희는 [320i, 340i, M3] 이렇게 3가지 모델을 가지고 있습니다 ! // Car benz = Car('Benz', ['A-Class', 'C-Class', 'E-Class', 'S-Class']); print(benz.name); // Benz print(benz.models); // [A-Class, C-Class, E-Class, S-Class] benz.introduceName(); // 안녕하세요, 저희는 Benz 입니다 ! benz.introduceModels(); // 저희는 [A-Class, C-Class, E-Class, S-Class] 이렇게 4가지 모델을 가지고 있습니다 ! }
아래의 기능이 들어있는 콘솔 프로그램 만들기
- 판매하는 상품 목록을 볼 수 있는 기능
- 구매자가 구매하고 싶은 상품들을 장바구니에 담을 수 있는 기능
- 구매자가 장바구니에 담은 상품들의 총 가격을 볼 수 있는 기능
✅ 쇼핑몰을 정의하기 위한
ShoppingMall클래스
📁 속성
✔ 판매하는 상품 목록 (List<Product>)
✔ 장바구니에 담은 상품들의 총 가격 (int)
📁 메서드
✔ 상품 목록을 출력하는 메서드showProducts()
✔ 상품을 장바구니에 담는 메서드addToCart()
✔ 장바구니에 담은 상품의 총 가격을 출력하는 메서드showTotal()
✅ 상품을 정의하기 위한
Product클래스
📁 속성
✔ 상품 이름String
✔ 상품 1개당 가격int
1. 판매하는 상품 목록을 볼 수 있는 기능
[ 설명 ]
✔1을 입력했을 때 판매하고 있는 상품 목록을 출력합니다.
[ 조건 ]
✔ 출력 형태 :[상품명] / [상품 1개당 가격]원셔츠 / 45000원 원피스 / 30000원 반팔티 / 35000원 반바지 / 38000원 양말 / 5000원[ 힌트 ]
✔ 반복문을 통해 상품의 정보를 하나씩 출력합니다.
2. 상품을 장바구니에 담을 수 있는 기능
[ 설명 ]
✔2를 입력했을 때 장바구니에 담을 상품 이름String과 상품 개수int를 입력 받습니다.
[ 조건 ]
✔ 입력한 상품의 이름이 상품 목록에 있지 않거나 상품의 개수가 0 이하의 값이면 장바구니에 담기지 않습니다.
✔ 상품 목록에 없는 상품의 이름을 입력한 경우입력값이 올바르지 않아요 !를 출력합니다.
✔ 상품의 개수를 숫자 형태로 입력하지 않은 경우입력값이 올바르지 않아요 !를 출력합니다.
✔ 입력한 상품의 개수가 0 이하의 수인 경우0개보다 많은 개수의 상품만 담을 수 있어요 !를 출력합니다.
✔ 입력한 상품의 이름과 상품의 개수가 올바른 값이면 장바구니에 담깁니다.
✔ 이 경우장바구니에 상품이 담겼어요 !를 출력합니다.
[ 힌트 ]
✔ 조건문과try-catch문을 통해 입력값에 대한 처리를 할 수 있습니다.
✔contains()또는 고차 함수를 통해 입력한 상품의 이름이 상품 목록에 있는지 판별할 수 있습니다.
✔int.parse()를 통해 입력한 상품의 개수를int타입으로 변환할 수 있습니다.
✔ 장바구니에 담은 상품들의 총 가격을 담기 위한 인스턴스 변수를ShoppingMall클래스에 정의한 후 그 인스턴스 변수의 값에 더해줍니다.
3. 장바구니에 담은 상품들의 총 가격을 볼 수 있는 기능
[ 설명 ]
✔ 3 을 입력했을 때 구매자가 장바구니에 담은 상품들의 총 가격 (int) 을 계산하여 출력합니다.
[ 조건 ]
✔ 출력 형태 : 장바구니에 [가격]원 어치를 담으셨네요 !장바구니에 35000원 어치를 담으셨네요 !
4. 쇼핑몰 프로그램을 종료할 수 있는 기능
[ 설명 ]
✔4를 입력했을 때 쇼핑몰 프로그램이 종료됩니다.
[ 조건 ]
✔이용해 주셔서 감사합니다 ~ 안녕히 가세요 !출력 후 프로그램을 종료합니다.
[ 힌트 ]
✔while문을 사용하고, 프로그램을 종료하기 위한bool타입의 변수로while문을 제어합니다.
- 터미널이나 명령 프롬프트 등의 명령줄 인터페이스를 사용하여 구현합니다.
- 입력 받는 기능은
dart:io라이브러리의stdin.readLineSync()를 사용합니다.
stdin.readLineSync()는 입력한 값을String?타입의 값으로 반환하는 메서드입니다.- 쇼핑몰에는 5개 이상의 상품이 있어야 하며, 생성자를 통해 생성합니다.
4를 입력하기 전까지는 쇼핑몰의 3가지 기능을 계속 사용할 수 있어야 합니다.1,2,3,4외의 값을 입력했을 때지원하지 않는 기능입니다 ! 다시 시도해 주세요 ..를 출력합니다.1,2,3,4를 입력 받을 때 각 숫자가 어떤 기능을 하는지 출력합니다.
dart create -t console-full 프로젝트 이름dart create -t console-full shopping_mall💭 우선
shopping_mall이란 이름으로 콘솔 프로그램을 만들었다.
shopping_mall/ ┣ bin/ ┃ ┗ shopping_mall.dart ← 메인 코드(여기에 작성) ┣ pubspec.yaml ┗ ...💭 여기에 해당 코드를 작성해보겠다.
dart run bin/shopping_mall.dart💭 이렇게 run을 돌리면 실행되어 값이 나온다고 한다.
폴더 역할 bin/ 실행 파일 (main 함수) lib/ 기능, 로직, 클래스, 함수 모음 test/ 기능이 잘 작동하는지 확인하는 테스트 코드 💭 이런 식이라서 콘솔을 사용할 땐 bin에서 작업하는 것 같은데... 복잡해지면 lib에 작성하고 bin에 가져오는 식? 으로 작업한다는데 아직 감이 안잡힌다.
과제 저장소
💬 예전에 한번 어떻게 사용하는지 궁금해서 써본 것 외에 본격적으로 쓰는 것은 이번이 처음인데, 기억이 잘 안나서 좀 헤멨다.
사실 많이.. 사용법이 기억이 안나서 GPT한테 물어봤는데 아까 콘솔에 대해서 물어봤다가 자꾸 콘솔 용어나.. 명령 프롬프트를 사용한 방식?을 자꾸 알려줘서...
나는 포크 프로그램을 사용하는데, 이게 Git 사용하는데 편리하다고 했던 것 같다.
✅ Git 저장소 만들기(
README.md체크) > 파일 업로드 > Fork Clone > 프로젝트 Clone 완료
💬 대충 이런식이다. README를 생성하지 않으니, 파일 업로드가 막히고, Fork에서 클론할 때 폴더를 잘못 선택해서 원본 프로젝트 안에 폴더가 생기기도 하고 문제가 좀 있었다.
📁 solo_proj_shopping_mall
💬 위와 같은 이름의 저장소와 클론 파일이 생겨 이제 코딩 작업을 시작할 수 있게 되었다.
dart pub getflutter pub add get✅ 시작하면 오류가 뜨는데 라이브러리를 설치하면 해결된다. 강의에서는 아래 코드를 터미널에 입력했다.
import 'dart:io';✅ 콘솔에서 출력값을 받기 위해 해당 라이브러리가 필요하다.
💬 콘솔에서 출력하기 위한stdout.write(), 값을 받아오는stdin.readLineSync()를 사용한다.
✅ 쇼핑몰 메뉴, 상품 목록 출력 구현
✅ 프로그램 입력 및 종료 기능 구현
📁 lib/shopping_mall
✅ bin 폴더 파일에서 코드가 길어질 것 같아서 lib에 쓰고, 해당 파일을 import하여 사용하기로 했다.
class ShoppingMall {
List<Product> products = [];
int totalPrice = 0;
ShoppingMall() {
products.add(Product("셔츠", 45000));
products.add(Product("원피스", 30000));
products.add(Product("반팔티", 35000));
products.add(Product("반바지", 38000));
products.add(Product("양말", 5000));
}
void showProducts() {
for (var p in products) {
print("${p.name} / ${p.price}원");
}
} // 상품 목록
void addToCart() {
// for (var i = 0; i < products.length; i++) {
// var pd = products[i];
// products[i].name , products[i].price
// }
}
void showTotal() {
//
}
} // 쇼핑몰 클래스
class Product {
String name;
int price;
Product(this.name, this.price);
} // 상품 클래스
💬 우선 과제 필수 정의를 위해
ShoppingMall클래스를 만들고, 속성에 판매 상품 목록List<Product> products와 총 가격을 넣을totalPrice을 만들었다.
밑에는ShoppingMall생성자를 만들어products에 상품명과 가격을 추가했다.
그리고 메서드 틀을 만들었고, 우선 상품 목록을 출력하는 메서드showProducts()를 구현했다.
상품 정의를 위한Product클래스도 만들어 생상자String타입name,int타입price속성을 만들었다.
❌ 이때
print("${p.name} / ${p.price}");이 부분이 출력이 안되어서 문제가 발생했었는데, 상품들을main()에서 추가해서 해당 클래스에서 활용할 수가 없었다.
그래서 내부에 생성자로 추가해주고, 혹은 bin 폴더에 상품을 추가하는 방법도 있었는데, 이게 코드가 보기에 깔끔하고, bin 폴더의 dart파일이 길어지니 쇼핑몰 클래스에 넣어줬다.
p에 리스트products를 반복문을 통해 모든 상품을 출력할 수 있도록showProducts()메서드를 구현했다.
❗ 강의에서는 클래스를 만들어주고 main에서 생성자에 값을 넣어 만드는 식으로 했다면, 이번에는 잘못 생각한게 실행할 main 파일이 해당 코드를 구현하는 이 파일이 아닌점,
class ShoppingMall { List<Product> products = []; int totalPrice = 0; }이런식으로 하면
ShoppingMall에는product의name,price라는게 없기 때문에 사용할 수 없다는 것이다.
📁 bin/shopping_mall
import 'dart:io';
import 'package:shopping_mall/shopping_mall.dart';
void main(List<String> arguments) {
stdout.write(
"[1] 상품 목록 보기 / [2] 장바구니에 담기 / [3] 장바구니에 담긴 상품의 총 가격 보기 / [4] 프로그램 종료"); // run 출력값
var shoppingMall = ShoppingMall();
while (true) {
String? numberInput = stdin.readLineSync();
if (numberInput == "1") {
shoppingMall.showProducts();
} else if (numberInput == "2") {
print("상품 이름과 상품 개수를 입력해주세요.");
} else if (numberInput == "3") {
print("장바구니에 $ShoppingMall.totalPrice원 어치를 담으셨네요 !");
} else if (numberInput == "4") {
print("이용해 주셔서 감사합니다 ~ 안녕히 가세요 !");
break;
} else {
print("지원하지 않는 기능입니다 ! 다시 시도해 주세요 ..");
} // 입력값 대응
}
💬 여기서
run을 돌릴거기 때문에 출력 및 입력 기능을 구현했다. lib 폴더에 있는 파일을 사용하기 위해import를 했다.
우선 해당 기능을 위해import 'dart:io';가 import 되어 있어야 사용 가능 하기 때문에 추가해주었다.stdout.write를 사용하면 출력이 가능하기 때문에 쇼핑몰 메뉴 출력을 해당 코드를 통해 구현했다.
그리고 쇼핑몰 클래스를 사용하기 위해, 변수에ShoppingMall();을 넣어주어서 해당 상품목록들을 사용할 수 있게 했다.
if문을 활용해서 입력값마다 대응하는 값을 출력하도록 만들었고, 기능 종료를 위해서while반복문을 통해서 4를 누르지 않는 한 계속 프로그램이 작동하도록 했다.
이를 위해 값을 true로 해서 계속 반복하게 하고, 4가 들어왔을 때break;하여 종료되도록 구현했다.
❗ 이때
ShoppingMall();이걸 가져오지 않은채로 그냥 ShoppingMall.name이나 ShoppingMall.products 같이 코드를 짜서 아무것도 되지 않고 자꾸 오류가 발생했다. import를 했어도 값을 사용하려면 불러와서 해당 변수를 사용해야 활용할 수 있는 것 같다.
❗ 입력값을 받기 위해
stdin.readLineSync();이걸 사용했어야 했는데 String 타입이라서 오류가 생겨서 아무것도 되지 않았다. 그래서 else 를 만들어 그 외의 입력값이 들어오는 것을 확인했고, 해당 입력값이 숫자라서 생기는 문제를 인식했다.
int number = int.parse(numberInput!);그래서 이렇게 int로 형변환을 했는데, 이제 문자를 입력하면 이게 오류가 발생하는 것이다. 오직 숫자만 입력될 것이라고 생각했는데 그게 아니었던 것이다.
그래서 해당 코드를 삭제하고,String타입으로 받되 숫자를"1"이렇게 문자로 받아버리는 것이다. 그러면 문자에도 대처가 가능하고, 그 외 숫자에도 대처가 가능하게 되는 것이다.놀라운 깨달음!
💬 그렇게 출력과 입력값을 받았을 때 메세지가 잘 작동하도록 구현을 해서 1번까지의 기능을 하도록 만들었고, 이제 나머지 기능을 작동하도록 구현하면 될 것 같다.
기반 작업
- 쇼핑몰 메뉴, 상품 목록 출력 구현
- 프로그램 입력 및 종료 기능 구현
🌱 오늘은 이론이나 문법쪽 강의까지 듣고 개인 과제를 시작했다.
실제 프로젝트.. 라고 하기엔 뭐하지만 실제 작업을 진행해보니 시작부터 상당히 고난이 있었고 어려웠다.
그래도 오류가 발생했을 때, 좀 더 생각해보고 이것저것 고쳐가면서 해결하면 뿌듯하기도 하고 재밌었다.
물론 내일이 되면 생각이 달라질 수도 있지만... 아무튼 하나 만드는데 시간이 상당히 걸리고, 고민도 많이 되고, 해결도 오래걸리고... 아직 손에 안익숙해서도 있는 것 같다.
🚀 내일은 과제를 마무리하고 제출할 생각이다. 금요일 오전에 추가 작업해서 마감 전에 제출하는 것은 무리가 있어보여서, 내일 마무리하고 제출해야될 것 같다.
오늘 기반 작업하는데 상당히 시간이 걸리고, 기능 하나하나 구현하는데 힘들었는데 가능할지 모르겠다... 최대한 열심히 해봐야지!