25.06.09 (6) - 추가학습

김영하·2025년 6월 9일

C++

목록 보기
25/32

1. SOLID 원칙을 적용한 Student 클래스 구현

"단일 책임 원칙"
각 클래스가 단 하나의 책임만 가지며
하나의 역할만 수행해야 한다.

이 원칙이 제대로 적용된 '학생 정보 관리 프로그램' 을 구현하기

요구사항)

  • Student 클래스:
    학생의 이름과 나이를 저장
    학생 정보를 문자열로 반환

  • StudentPrinter:
    학생 정보를 출력
    Student 클래스와는 별도로 분리
    배터리를 충전하는 메서드(함수)

  • 사용자가 Student 객체를 생성하고
    이를 StudentPrinter 로 출력할 수 있도록 구현


  • 1단계 코드
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Student {
private:
	string name;
	int age;

public:
	Student(string studentName, int studentAge)
		: name(studentName), age(studentAge) {};

	string getName() {
		return name;
	}

	int getAge() {
		return age;
	}

	string getInfo() {
		cout << "학생 이름: " << getName() << endl;
		cout << "학생 나이: " << getAge() << endl;
	}
};

class StudentPrinter {
public:
	void print(Student* student) {
		student->getInfo();
	}
};

int main() {
	Student s = Student("John Doe", 20);
	StudentPrinter::print(&s); // 이 부분이 문제
	return 0;
}
  • 정답 코드와 비교하며 분석
#include <iostream>
#include <string>

using namespace std;

// 학생 정보를 저장하는 클래스
class Student {
private:
    string name;
    int age;

public:
    // 생성자
    Student(string studentName, int studentAge) : name(studentName), age(studentAge) {}

    // 학생 이름 가져오기
    string getName() {
        return name;
    }

    // 학생 나이 가져오기
    int getAge() {
        return age;
    }

    // 학생 정보를 문자열로 반환
    string getInfo() {
        return "학생 이름: " + name + "\n학생 나이: " + to_string(age);
    }
};

// 학생 정보를 출력하는 클래스
class StudentPrinter {
public:
    // 학생 정보를 출력
    void print(Student& student) {
        cout << student.getInfo() << endl;
    }
};

int main() {
    // Student 객체 생성
    Student student("John Doe", 20);

    // StudentPrinter 객체 생성
    StudentPrinter printer;

    // 학생 정보 출력
    printer.print(student);

    return 0;
}

일단 프린터 클래스의 print 함수 부분에서,
포인터를 사용할 게 아니라 참조자를 사용해 주었어야 했는데,
이는 오늘자 라이브세션 내용중

동적 할당이나 재할당이 필요한 게 아니라면 "참조자"부터 고려하자

이 내용을 생각하면 될 것 같다
따라서 아래와 같이 수정

string getInfo() 함수도 리턴값이 필요하기 때문에
출력 예시의 문자열이 나올 수 있도록 수정

Student 객체도 저렇게 좀더 간단하게 할 수 있는 모양
어찌 되었든 프린터 객체도 생성해줄 필요가 있고
프린터에서 . 으로 print 함수 불러와서 student 객체 넣어주는 방식으로 마무리


2. TODO 리스트 구현

필수 요구사항)

  • 할 일 추가 기능
  • 할 일 목록 확인 기능
  • 할 일 완료 처리 기능

클래스 설계)

  • Task 클래스:
    할 일의 데이터를 관리, 할 일의 내용과 완료 여부 포함

  • IStorage 클래스:
    할 일을 저장하고 불러오는 동작을 추상화
    현재 어떤 Storage를 사용하고 있는지 반환

  • MemoryStorage 클래스:
    할일을 메모리에 저장
    IStorage 인터페이스를 구현한 간단한 버전

  • DBStorage:
    할일을 DB에 저장
    (실제 DB를 구축하는 게 아니고) DB를 사용하고 있다고만 반환

  • TaskManager:
    Task 객체를 추가, 조회, 완료 처리하는 기능 제공

[실제 제공된 메인함수의 출력 예시 입니다]

=== MemoryStorage로 작업 ===

현재 할 일 목록:
저장 방식: 메모리 저장소
1. C++ 과제 작성하기
2. SOLID 원칙 공부하기

업데이트된 할 일 목록:
저장 방식: 메모리 저장소
1. C++ 과제 작성하기
2. SOLID 원칙 공부하기
3. C++ 과제 작성하기 [완료]

=== DBStorage로 작업 ===
DB에 할 일 추가: DB 작업 테스트
DB에 할 일 추가: To-Do 목록 추가

현재 할 일 목록:
저장 방식: DB 저장소 (시뮬레이션)
DB에서 할 일 가져오기
1. DB 작업 테스트
2. To-Do 목록 추가
DB에서 할 일 가져오기
DB에 할 일 추가: To-Do 목록 추가

업데이트된 할 일 목록:
저장 방식: DB 저장소 (시뮬레이션)
DB에서 할 일 가져오기
1. DB 작업 테스트
2. To-Do 목록 추가
3. To-Do 목록 추가 [완료]

제공된 메인함수와 TaskManager 클래스 코드를 참고해서
어떻게 완성에는 성공했다

Task 클래스

IStorage 클래스

MemoryStorage DBStorage

TaskManager

메인 함수

클래스다이어그램 토대로 클래스들 선언부터 완성하고
IStorage는 어차피 전부 순수가상함수,

Task 클래스는 완료여부 초기화시 false로 되는거만 신경써주고
나머지는 함수이름대로
완료처리랑 getter 함수들

MemoryStorage 랑 DBStorage의 경우,
IStorage의 가상함수들을 override 재정의 해준 것들,
addTask 에 인자로 task 객체가 들어오면
멤버 변수 타입이 vector<Task> 이기 때문에 그냥 그대로 추가해주고
아래 2개는 고민 과정이 조금 있었지만
생각해보니 단순한 getter 함수여서 그대로 필요한 것들 return

TaskManager의 경우,
제공을 받은 코드기 때문에 분석을 적어두자면:
인터페이스인 IStorage의 포인터를 받아서 참조를 통해 값을 확인하는 방식이고
description 이 변경될 수 없도록 const 걸어주면서
인터페이스에 있는
addTask, getStorageType, getTasks 함수 활용해주고
그렇게 tasks 벡터 채운뒤에는 목표로 하는 출력 예시 형태에 맞게
task들 하나씩 출력해주고

completeTask 함수의 경우
tasks 벡터는 함수 안이 생존 주기이기 때문에 다시 task들 모아주고
파라미터에 있는 index는 우리가 '접근'에 활용하는 인덱스가 아니라 그냥 번호.
해당 번호에 맞는 task를 찾아 complete 처리 해주기 위해
tasks[index-1] 로 찾아서 complete처리해주고
addTask로 갱신;

profile
내일배움캠프 Unreal 3기

0개의 댓글