DINO NET

SOLID - 1. Single Responsibility Principle (단일 책임 원칙) 본문

program()/파이썬

SOLID - 1. Single Responsibility Principle (단일 책임 원칙)

2023. 2. 7. 23:16

SOLID 원칙

Robert C. Martin 이라는 개발자가 2000년도에 처음 발표한 객체 설계의 기본 5 원칙.

1. 단일 책임 원칙 Single Responsibility Principle 
2. 개방 폐쇄 원칙 Open-Closed Principle
3. 리스코프 치환 원칙 Liskov Substitution Principle
4. 인터페이스 분리 원칙 Interface segregation Principle
5. 의존 관계 역전 원칙 Dependency Inversion Principle 

 

단일 책임 원칙 Single Responsibility Principle

모든 클래스는 단 한가지의 책임만을 갖고, 클래스 안에 정의되어 있는 모든 기능은, 이 하나의 책임을 수행하는데 집중되어 있어야 한다. -> 하나의 클래스로는 딱 한 가지 책임만 수행해야 한다.

<-> God object: 하나의 클래스가 많은 책임을 직접 수행하는 것을 비유적으로 이르는 말

 

클래스가 방대해질 수록 유지보수가 어렵고 놓친 부분이 생기기 마련이므로 클래스를 쪼개서 만드는 것이다.

단일 책임이란 매우 주관적인 단위이므로 개발자 마다 다른 기준을 가지고 있을 가능성이 농후하다.

 

 

코드잇 예제 실습

God object

class Student:
    def __init__(self, name, id, major):
        self.name = name
        self.id = id
        self.major = major
        self.grades = []

    def change_student_info(self, new_name, new_id, new_major):
        """학생 기본 정보 수정 메소드"""
        self.name = new_name
        self.id = new_id
        self.major = new_major

    def add_grade(self, grade):
        """학점 추가 메소드"""
        if 0 <= grade <= 4.3:
            self.grades.append(grade)
        else:
            print("수업 학점은 0과 4.3 사이여야 합니다!")

    def get_average_gpa(self):
        """평균 학점 계산 메소드"""
        return sum(self.grades) / len(self.grades)

    def print_report_card(self):
        """학생 성적표 출력 메소드"""
        print("코드잇 대학 성적표\n\n학생 이름:{}\n학생 번호:{}\n소속 학과:{}\n평균 학점:{}"\
        .format(self.name, self.id, self.major, self.get_average_gpa()))
        

## 학생 인스턴스 정의
younghoon = Student("강영훈", 20120034, "통계학과")
younghoon.change_student_info("강영훈", 20130024, "컴퓨터 공학과")

## 학생 성적 추가
younghoon.add_grade(3.0)
younghoon.add_grade(3.33)
younghoon.add_grade(3.67)
younghoon.add_grade(4.3)

## 학생 성적표 
younghoon.print_report_card()

 

직접 해본 답

class Student:
    def __init__(self, name, id, major):
        self.name = name
        self.id = id
        self.major = major
        self.grade = Grade()
    
    def change_student_info(self, new_name, new_id, new_major):
        """학생 기본 정보 수정 메소드"""
        self.name = new_name
        self.id = new_id
        self.major = new_major
    
    def print_report_card(self): 
        """학생 성적표 출력 메소드"""
        print("코드잇 대학 성적표\n\n학생 이름:{}\n학생 번호:{}\n소속 학과:{}\n평균 학점:{}"\
        .format(self.name, self.id, self.major, self.grade.get_average_gpa()))


class Grade:
    """학점 관리 클래스"""
    def __init__(self):
        self.grades = []
    
    def add_grade(self, grade):
        """학점 추가 메소드"""
        if 0 <= grade <= 4.3:
            self.grades.append(grade)
        else:
            print("수업 학점은 0과 4.3 사이여야 합니다!")
    
    def get_average_gpa(self):
        """평균 학점 계산 메소드"""
        return sum(self.grades) / len(self.grades)


#학생 인스턴스 정의
younghoon = Student("강영훈", 20120034, "통계학과")
younghoon.change_student_info("강영훈", 20130024, "컴퓨터 공학과")

#학생 성적 추가
younghoon.grade.add_grade(3.0)
younghoon.grade.add_grade(3.33)
younghoon.grade.add_grade(3.67)
younghoon.grade.add_grade(4.3)

#학생 성적표
younghoon.print_report_card()

 

예제라 하나하나 뜯어봐야 했겠지만, 여기서는 굳이 더 분리할 필요가 없다고 생각해서 grade만 따로 떼어 놓았다.

 

코드잇 답

class StudentProfile:
    """학생 기본 정보 클래스"""
    def __init__(self, name, id, major):
        self.name = name
        self.id = id
        self.major = major

    def change_info(self, new_name, new_id, new_major):
        """학생 기본 정보 수정 메소드"""
        self.name = new_name
        self.id = new_id
        self.major = new_major
        
        
class GPAManager:
    """학생 학점 관리 클래스"""
    def __init__(self, grades):
        self.grades = grades

    def add_grade(self, grade):
        """학점 추가 메소드"""
        if 0 <= grade <= 4.3:
            self.grades.append(grade)
        else:
            print("수업 학점은 0과 4.3 사이여야 합니다!")

    def get_average_gpa(self):
        """평균 학점 계산"""
        return sum(self.grades) / len(self.grades)  
    
    
class ReportCardPrinter:
    """성적표 출력 클래스"""
    def __init__(self, student_profile, gpa_manager):
        self.student_profile = student_profile
        self.gpa_manager = gpa_manager

    def print(self):
        """학생 성적표 출력 메소드"""
        print("코드잇 대학 성적표\n\n학생 이름:{}\n학생 번호:{}\n소속 학과:{}\n평균 학점:{}"\
        .format(self.student_profile.name, self.student_profile.id,\
                self.student_profile.major, self.gpa_manager.get_average_gpa()))   
    

class Student:
    """코드잇 대학생을 나타내는 클래스"""
    def __init__(self, name, id, major):
        self.profile = StudentProfile(name, id, major)
        self.grades = []
        self.gpa_manager = GPAManager(self.grades)
        self.report_card_printer = ReportCardPrinter(self.profile, self.gpa_manager)


# 학생 인스턴스 정의
younghoon = Student("강영훈", 20120034, "통계학과")
younghoon.profile.change_info("강영훈", 20130024, "컴퓨터 공학과")

# 학생 성적 추가
younghoon.gpa_manager.add_grade(3.0)
younghoon.gpa_manager.add_grade(3.33)
younghoon.gpa_manager.add_grade(3.67)
younghoon.gpa_manager.add_grade(4.3)

# 학생 성적표 
younghoon.report_card_printer.print()

 

 

 

0207