mjello 님의 개발 블로그

[소프트웨어 아키텍처 03] UML/SOLID Design Principles/GRASP 본문

소프트웨어 아키텍처 🗃️

[소프트웨어 아키텍처 03] UML/SOLID Design Principles/GRASP

mjello 2024. 11. 20. 16:08

*  최은미 교수님의 소프트웨어 아키텍처 수업을 듣고, 개발 시 참고하기위해 간단히 정리했습니다.

08 UML

Use Case Diagram

  1. actor 행위자 (시스템과 교류하는 사람 or 시스템 or 장치)
  2. Use Case (행위)
  3. 시스템
  • 바운더리 클래스 (외부와 상호작용)
  • 엔터티 클래스 (주요 추상개념)
  • 컨트롤 클래스 (유스케이스 행위)

보통 Association이랑 Realization 많이 씀

Association : A → B 와 같이 방향이 있는 실선의 경우, A가 B를 참조한다는 의미

Inheritance : 부모 클래스와 자식 클래스 간의 상속 관계

Realization : 인터페이스를 상속하여 클래스에서 실제 기능을 실현화 할 때 사용

Dependency : 클래스간 참조 관계

Aggregation : 집합 관계

Composition : 더 강력한 집함, 종속적

- 나 죽 손 죽, 손 죽 나 안죽, 나← 손

 

Association 관계는 해당 클래스의 멤버 변수로 할당할 때 사용하고 

Dependency 관계는 로컬 변수, 파라미터, 반환 값으로 호출되는 메소드가 실행되는 동안에만 유지가 될 때 사용

 

 

 

 

 

09 GRASP

 

General Responsibility Assignment Software Patterns (GRASP)

: 객체지향 설계에서 책임 할당을 위한 디자인 원칙

  • 책임 할당의 중요성: 객체의 역할과 작업을 올바르게 분배하여 변경 가능성과 재사용성을 높임

 

GRASP Patterns
  1. Low Coupling : 클래스 간의 의존성을 최소화해 유지보수성과 재사용성 향상
    • 의미: 클래스가 다른 클래스에 얼마나 의존하는지
    • 문제점: 높은 결합도는 클래스 변경 시 다른 클래스에도 영향을 미침
    • 원칙: 책임을 할당할 때 결합도를 최소화
  2. High Cohesion : 클래스 내의 책임을 집중시켜 복잡성을 줄이고 이해 및 유지보수 용이성 향상
    • 의미: 클래스의 책임이 얼마나 관련되어 있는지
    • 문제점: 낮은 응집도는 유지보수와 재사용에 불리
    • 원칙: 클래스의 책임을 명확하게 정의해 응집도를 높임
  3. Expert : 정보를 가장 잘 알고 있는 클래스에 책임을 할당하여 캡슐화 유지 및 결합도 감소
    • 원칙: 필요한 정보를 가진 클래스에 책임을 할당
    • 이점: 캡슐화 유지, 결합도 감소, 높은 응집도
  4. Creator : 객체 생성 책임을 집계하거나 사용하는 클래스에 부여
    • 원칙: 한 클래스가 다른 클래스의 인스턴스를 생성할 책임을 가짐
    • 조건: 집계, 포함, 기록, 밀접하게 사용하는 클래스가 인스턴스를 생성
  5. Controller : 외부 이벤트를 처리하고 내부 이벤트로 연결하는 역할
    • 역할: 외부 이벤트를 내부 이벤트로 전달하는 중개 역할
    • 이점: 비즈니스 로직의 캡슐화, 유스 케이스 관리 및 재사용 가능성
  6. Don’t Talk to Stranger : 중간계층을 통해 간접적으로 클래스 간 상호작용을 유도해 결합도 감소
    • 원칙: 클래스 간 직접 상호작용을 피하고 중간 클래스를 사용해 간접적으로 통신
    • 이점: 결합도 감소

 

 

SOLID Design Principles

 

SOLID는 객체지향 설계에서 중요한 5가지 원칙을 나타냄.

  1. The Single Responsibility Principle (SRP) 단일 책임 원칙
    • 클래스는 하나의 책임만 가져야 함
    • 변경 이유는 하나여야 함
    • 예: 데이터 읽기와 화면 표시 기능을 분리해야함⇒ 필요한 패키지만 골라서 사용 가능
    • 반례 : 절차지향에서 상위 데이터 구조 변경 시 하위 코드들 모두 변경해야하는 상황 발생 등
  2. The Open/Closed Principle (OCP) 개방.폐쇄 원칙
    • 확장에는 열려 있고, 변경에는 닫혀 있어야 
    • 기능 추가 시 기존 코드는 수정하지 않도록 설계
    • 예: 추상화로 데이터 변경해도 클래스는 영향 없도록
    • 상속을 통해 sendHeader, sendBody 오버라이딩해서 기능 추가
    • 반례 : 다운캐스팅, 저렇게 조건으로 별도 처리하는거, 변경에 닫혀있지않은 경우
  3. The Liskov Substitution Principle (LSP) 리스코프 치환 원칙
    • 상위 타입의 객체를 하위 타입으로 치환해도 정상 동작해야 함
    • 메서드에 하위 타입의 객체를 전달해도 someMethod()가 정상적으로 동작해야 한다.
    • 반례: 직사각형 대신 정사각형 사용 시 동작이 일관되지 않으면 위반
    • instanceof 연산자를 사용한다는 것은 리스코프 치환 원칙 위반이 되곤 한다.
  4. The Interface Segregation Principle (ISP) 인터페이스 분리 원칙
    • 인터페이스는 그 인터페이스를 사용하는 클라이언트가 필요로 하는 기능만 제공해야 함
    • 불필요한 메서드 의존성을 없애야 함클라이언트 입장에서 인터페이스를 분리한다는 원칙
  5. The Dependency Inversion Principle (DIP) 의존성 역전 원리
    • 고수준 모듈이 저수준 모듈에 의존하지 않고, 추상화에 의존해야 함 (저는 고에 의존 O)
    • 의존성을 역전시켜 유연성 확보
      • 소스 코드 상에서의 의존은 역전되었지만,
      • 런타임에서의 의존은 고수준 모듈의 객체에서 저수준 모듈의 객체로 향한다.
      • 런타임의 의존이 아닌 소스 코드의 의존을 역전시킴으로써
      • 변경의 유연함을 확보할 수 하는 원칙