📌 객체 지향(Object - Oriented) 설계
객체(Object)와 객체 지향(Object - Oriented) 설계
객체란, 데이터와 데이터를 처리하는 함수를 묶어놓은 하나의 소프트웨어 모듈입니다.
객체의 가장 중요한 특징은 아래 세 가지를 반드시 갖고 있다는 것입니다!
- 속성
- 동작
- 고유 식별자
EX)
- 객체(Object) : 사람
- 속성(Property) : 이름(홍길동), 나이(30), 성별(남성)
- 동작(Method) : 걷기(), 말하기(), 코딩하기()
객체 지향 설계란, 소프트웨어를 여러 객체로 나누고, 이 객체들이 서로 상호작용하게 하여 프로그램을 만드는 방법을 말합니다.
객체 지향 구성요소
- 객체(Object) : 실세계에 존재하거나 생각할 수 있는 것
- 메서드(Method) : 객체가 수행할 수 있는 동작이나 기능 (메세지를 받아 실행할)
- 속성(Property) : 객체들의 상태를 나타내는 데이터
- 클래스(Class) : 하나 이상의 유사한 객체들을 묶어 공통된 특성을 표현한 것
- 인스턴스(Instance) : 클래스에 속한 각각의 객체
- 메세지(Message) : 객체에게 어떤 행위를 하도록 지시하는 명령
객체 지향 설계의 원칙(SOLID)
=> 객체 지향 설계를 위한 5가지 원칙으로, 유지보수성과 확장성에 도움을 줌
- 단일 책임의 원칙(Single Responsibility Principle)
: 하나의 클래스는 하나의 책임만, 즉 하나의 기능이나 역할만 담당해야 함 - 개방-폐쇄의 원칙(Open Close Principle)
: 클래스는 확장에 대해 열려 있어야 하며, 변경에 대해 닫혀 있어야 함
(새로운 기능을 추가할 때 기존 코드를 수정하지 말아야 함) - 리스코프 치환의 법칙(Liskov Substitution Principle)
: 서브 타입(상속받은 하위 클래스)은 어디에서나 자신의 기반 타입(상위 클래스)로 교체할 수 있어야 함
(부모 클래스의 기능을 자식 클래스가 동일하게 수행할 수 있어야 함) - 인터페이스 분리의 법칙(Interface Segregation Principle)
: 클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 함
(필요 없는 기능은 과감하게 제거되어야 함) - 의존성 역전의 원칙(Dependency Inversion Principle)
: 구체적인 클래스보다는 인터페이스나 추상 클래스에 의존해야 함
📌 객체 지향 설계의 특징
- 다형성
- 캡슐화
- 상속
- 추상화
- 정보은닉
- 관계성(연관화, 집단화, 분류화, 일반화, 특수화)
다형성(polymorphism)
=> 하나의 부모 객체(클래스)가 여러 형태로 동작할 수 있게 하는 능력
- 코드의 유연성과 재사용성을 높임
오버라이딩(Overiding)
: 상위 객체(클래스)에서 정의한 메서드를 하위 객체(클래스)에서 재정의
오버로딩(Overloading)
: 같은 클래스 내에서 매개변수 유형과 개수를 다르게 하여 같은 이름의 메서드를 여러 개 정의
캡슐화(encapsulation)
=> 객체 속성과 메서드를 하나로 묶고, 실제 구현 내용의 일부를 외부에 감추어 은닉
(정보를 숨기고, 필요한 인터페이스만 밖으로 드러내는 과정)
- 객체 지향에서 정보 은닉과 가장 관계가 있음
<캡슐화의 장점>
- 인터페이스 단순화
- 소프트웨어의 재사용성 향상
- 변경 발생 시 오류의 파급효과가 적음
상속(inheritance)
=> 상위 객체의 메서드와 속성을 하위 객체가 물려받는 것
- 추가로 각자의 고유한 특성을 정의할 수 있음
- 코드의 재사용성을 높이고, 기존 객체를 확장하여 새로운 객체를 쉽게 만들 수 있음
추상화(abstraction)
=> 복잡한 시스템의 중요한 부분만 드러내고, 세부 사항은 감추는 것
(가장 본질적이고 공통적인 부분만 추출하여 표현)
- 소프트웨어 설계 시 추상화 기법으로는 자료, 제어, 과정 추상화가 있음
정보은닉(Information Hiding)
=> 객체가 가지고 있는 속성과 연산 일부를 감추어 객체의 외부에서는 접근 불가능하게 하는 개념
- 정보 은닉의 근본 목적은 고려되지 않은 영향(Side-effect) 최소화
- 모듈들 사이의 독립성을 유지시키는데 도움이 됨
- 요구사항 변화에 따라 모듈 내부의 자료 구조와 접근 동작들을 수정 가능
관계성(Relationship)
=> 클래스 or 객체 간에서 데이터를 참조하는 관계를 나타내는 기법
- 연관화 : 객체 간의 일반적인 관계 (is-member-of)
- 학생 - 교수
- 분류화 : 객체를 공통된 특성에 따라 그룹화 (is-instance-of)
- 동물을 포유류, 조류, 어류로 그룹화
- 집단화 : 전체와 부분의 관계로, 부분은 독립적으로 존재 가능 (is-a-part-of)
- 팀과 선수
- 일반화 : 여러 클래스의 공통된 특성을 추출하여 상위 클래스를 만드는 것 (is-a)
- 개와 고양이의 특성을 조합해 동물 클래스를 만듦
- 특수화 : 상위 클래스를 기반으로 더 구체적이고 특수한 하위 클래스를 만드는 것 (is-a)
- 동물 클래스를 특수화하여 개와 고양이 클래스를 만듦
📌 객체 지향 분석
객체 지향 분석이란, 소프트웨어 개발을 위해 비즈니스 문제를 객체와 속성, 클래스와 멤버, 전체와 부분 등으로 나누어서 분석하는 과정을 말합니다.
<객체 지향 분석의 특징>
- 시스템 내 객체들이 상호작용하는 방식을 설계하는 동적 모델링 기법이 사용될 수 있음
- 세부적인 객체들을 먼저 설계하고 전체 시스템을 통합시키는 상향식 방식
- 데이터와 행위를 하나로 묶어 객체를 정의하고 추상화시키는 작업
- 코드 재사용에 의한 프로그램 생산성 향상 및 요구에 따른 시스템의 쉬운 변경이 가능
객체 지향 분석 기법
- Coad - Yourdon 방법론
: ER 다이어 그램을 사용하여 객체의 행위를 데이터 모델링하는 데 초점을 둔 방법 - 럼바우(Rumbaugh) 방법론
: 객체 모델 → 동적 모델 → 기능 모델로 나누어 순서대로 분석을 수행하는 방법- 객체 모델 : 시스템에 필요한 객체를 찾아내어 속성과 관계를 규정하여 다이어그램으로 표시
- 동적 모델 : 상태 다이어그램, 사건 흐름 다이어그램 등을 통해 객체 간의 상호작용을 시간 순으로 표현
- 기능 모델 : 시스템의 기능을 자료 흐름도(DFD)를 통해 표현
- Booch 방법론 : 설계 문서화를 강조하여 다이어그램을 중심으로 개발
- Jacobson 방법론 : 유스케이스를 모든 모델의 근간으로 활용하는 방법론
📌 디자인 패턴
디자인 패턴이란?
디자인 패턴이란, 소프트웨어 설계에서 자주 발생하는 문제에 대한 일반적이고 반복적인 해결 방법
디자인 패턴 사용의 장점
- 소프트웨어 구조 파악이 용이함
- 객체 지향 설계 및 구현의 생산성을 높이는 데 적합
- 재사용을 위한 개발 시간이 단축
GoF(Gang of Four)의 디자인 패턴
=> 디자인 패턴을 생성, 구조, 행위의 3가지 구분과 23개의 패턴으로 분류
- 생성(Creational) 패턴
- 객체를 어떻게 생성하고 초기화할지에 대한 패턴들
- 구조(Structural) 패턴
- 클래스와 객체를 더 큰 구조로 조합하는 방법에 대한 패턴들
- 행위(Behavior) 패턴
- 객체 간의 상호작용과 책임 분배에 대한 패턴들
GoF의 주요 디자인 패턴
<생성 패턴>
- Factory method 패턴
: 객체를 생성하기 위한 인터페이스를 정의하여 어떤 클래스가 인스턴스화 될 것인지는 서브 클래스가 결정하도록 하는 것
# 문서의 기본 클래스를 정의 class Document: def create_document(self): pass # Word 문서 클래스 class WordDocument(Document): def create_document(self): print("Word 문서를 생성합니다.") # PDF 문서 클래스 class PdfDocument(Document): def create_document(self): print("PDF 문서를 생성합니다.") # 클라이언트 코드 def document_creator(document_type): if document_type == "word": return WordDocument() elif document_type == "pdf": return PdfDocument() doc = document_creator("word") doc.create_document() # "Word 문서를 생성합니다."
- Prototype 패턴
: prototype을 먼저 생성하고 인스턴스를 복제하여 사용하는 구조
- 예시 : 프로그래밍에서 게임 캐릭터가 많아질 때, 모든 캐릭터를 새로 생성하기보다는 기존 캐릭터를 복제(clone)하는 방식을 사용할 수 있음
import copy class Character: def __init__(self, name, power): self.name = name self.power = power def clone(self): return copy.deepcopy(self) # 원본 캐릭터 생성 warrior = Character("Warrior", 50) # 원본 캐릭터 복제 clone_warrior = warrior.clone() clone_warrior.name = "Warrior Clone" print(warrior.name, warrior.power) # Warrior 50 print(clone_warrior.name, clone_warrior.power) # Warrior Clone 50
- Singleton 패턴
: 한 클래스에 한 객체만 존재하도록 제한하는 패턴 (생성된 객체를 어디에서든지 참조할 수 있도록 함)
- 예시 : 애플리케이션에서 데이터베이스 연결을 관리하는 Database 클래스가 있다고 가정. 여러 곳에서 이 클래스의 객체를 사용하더라도, 같은 인스턴스 하나만 사용해야 함
class Database: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super(Database, cls).__new__(cls) print("데이터베이스 연결을 생성합니다.") return cls._instance # 두 개의 데이터베이스 인스턴스 생성 시도 db1 = Database() db2 = Database() print(db1 is db2) # True, 두 인스턴스는 동일
<행위 패턴>
- Strategy 패턴
: 다양한 알고리즘을 캡슐화하여 알고리즘 대체가 가능하도록 한 행위 패턴
- 예시 : 온라인 상점에서 결제 방식을 선택할 수 있는 경우를 가정. 카드 결제, 페이팔 결제 등 다양한 결제 전략이 존재하고, 사용자는 이를 선택할 수 있음.
# 결제 전략 인터페이스 class PaymentStrategy: def pay(self, amount): pass # 카드 결제 전략 class CreditCardPayment(PaymentStrategy): def pay(self, amount): print(f"Credit Card로 {amount}원을 결제합니다.") # 페이팔 결제 전략 class PayPalPayment(PaymentStrategy): def pay(self, amount): print(f"PayPal로 {amount}원을 결제합니다.") # 결제 컨텍스트 class ShoppingCart: def __init__(self, payment_strategy): self.payment_strategy = payment_strategy def checkout(self, amount): self.payment_strategy.pay(amount) # 클라이언트 코드 cart1 = ShoppingCart(CreditCardPayment()) cart1.checkout(10000) # Credit Card로 10000원을 결제합니다. cart2 = ShoppingCart(PayPalPayment()) cart2.checkout(20000) # PayPal로 20000원을 결제합니다.
- Mediator 패턴
: 객체들 간의 상호작용을 직접 하지 않고 중재자를 통해 처리하도록 만드는 패턴
(이로 인해 객체들이 서로를 참조할 필요가 없으며, 객체 간의 의존성을 줄이고 유지보수를 쉽게 할 수 있게 됨)- 예시 : 채팅 방에서 여러 사용자가 서로 대화하는 경우 가정. 모든 사용자가 서로 직접 메시지를 보내는 대신, ChatMediator라는 중재자를 통해 메시지를 전달받고 전달함.
# 중재자 인터페이스 class ChatMediator: def send_message(self, message, user): pass # 채팅 중재자 클래스 class ChatRoom(ChatMediator): def __init__(self): self.users = [] def add_user(self, user): self.users.append(user) def send_message(self, message, user): for u in self.users: if u != user: # 메시지를 보낸 사용자는 제외하고 전달 u.receive(message) # 사용자 클래스 class User: def __init__(self, name, chat_mediator): self.name = name self.chat_mediator = chat_mediator def send(self, message): print(f"{self.name}님이 메시지를 보냈습니다: {message}") self.chat_mediator.send_message(message, self) def receive(self, message): print(f"{self.name}님이 메시지를 받았습니다: {message}") # 클라이언트 코드 chat_room = ChatRoom() user1 = User("Alice", chat_room) user2 = User("Bob", chat_room) user3 = User("Charlie", chat_room) chat_room.add_user(user1) chat_room.add_user(user2) chat_room.add_user(user3) user1.send("안녕하세요!") # 출력: # Bob님이 메시지를 받았습니다: 안녕하세요! # Charlie님이 메시지를 받았습니다: 안녕하세요!
'License > 정보처리기사' 카테고리의 다른 글
[정보처리기사] 1과목 소프트웨어 설계 - 인터페이스 설계 (1) | 2024.11.30 |
---|---|
[정보처리기사] 4과목 프로그래밍 언어 활용 - 응용 SW 기초 기술 활용(네트워크) (1) | 2024.11.09 |
[정보처리기사] 1과목 소프트웨어 설계 - 애플리케이션 설계(공통 모듈 설계) (2) | 2024.11.04 |
[정보처리기사] 1과목 소프트웨어 설계 - 화면 설계 (1) | 2024.10.25 |