information processing

1-21,22. 객체지향 설계

nana-log 2022. 6. 27. 22:37

CHAPTER 07. 객체지향 구현
Section 1. 객체지향 설계

1. 객체지향 (Object Oriented Programming-OOP)

⑴ 객체지향 개념

- 현실 세계의 유형, 무형의 모든 대상을 객체(Object)로 나누고, 객체의 행동(method)과 고유한 값(Attribute)을
정의하여 설계하는 방법
- 객체를 만들고 조작하며 객체끼리 관계를 맺음으로써 다수의 객체가 함께 수행될 수 있게 한다.

⑵ 객체지향 구성요소

■ 클래스 (Class)
- 유사한 종류의 유형/무형의 존재를 속성과 연산을 정의해서 만든 틀
- 다른 클래스와 독립적으로 디자인 한다
- 데이터를 추상화 하는 단위
객체 (Object)
- 클래스의 인스턴스
- 객체는 자신 고유의 속성을 가지며, 클래스에서 정의한 연산을 수행
- 객체의 연산은 클래스에 정의된 연산에 대한 정의를 공유함으로써 메모리를 경제적으로 사용
속성 (Attribute)
- 객체들이 가지고 있는 고유한 데이터를 단위별로 정의한 것
- 성질, 분류, 수량, 현재 상태 등에 대해 표현한 값
메서드 (Method)
- 어떤 특정한 작업을 수행하기 위한 명령문의 집합
- 객체가 가지고 있는 속성들을 변경할 수 있는 하나의 연산
메시지 (Message)
- 객체에게 어떤 행위를 하도록 지시
- 객체의 메서드를 호출함으로써 객체간의 상호작용을 할 수 있도록 한다.

⑶ 객체지향언어의 특징

■ 캡슐화(Encapsulation)
- 데이터(Attribute)와 데이터를 처리하는 행동(method)을 하나로 묶은 것
- 캡슐화된 객체의 세부내용은 외부에 은폐(정보은닉)되어, 오류의 파급 효과가 적다.

- 캡슐화된 객체들은 재사용이 용이
- 객체들 간의 메시지를 주고 받을 때, 해당 객체의 세부 내용을 알 필요가 없으므로 인터페이스가 단순해지고,
결합도가 낮아진다.

정보은닉(Information Hiding)
- 캡슐화의 가장 중요한 개념
- 다른 객체에게 자신의 데이터를 숨기고, 자신이 정의한 행동만을 통하여 접근을 허용

상속(Inheritance)
- 상위클래스(부모클래스)의 모든 데이터와 행동을 하위 클래스가 물려받는 것
- 상속을 이용하면 하위 클래스는 상위 클래스의 데이터와 행동을 자신의 클래스에 다시 정의하지 않아도 된다.

- 하위 클래스는 상위 클래스에서 상속받은 요소 외에 새로운 데이터와 행동을 추가하여 사용할 수 있다.
- 상위클래스의 요소들을 사용할 수 있기 때문에, 소프트웨어 재사용을 증대시키는 중요한 개념

다형성(Polymorphism)
- 하나의 메시지에 대해 각 객체가 가지고 있는 여러 가지 방법으로 응답할 수 있는 개념
- 객체에서 동일한 메서드명을 인자값의 유형이나 개수만 틀리게 하는 오버로딩이 존재
- 객체에서 상속받은 메서드를 재정의 하는 오버라이딩이 존재

추상화(Abstraction)
- 어떤 실체로부터 공통적인 부분들만 모아놓은 것
- 하위클래스들에 존재하는 공통적인 메소드를 상위클래스 혹은 인터페이스로 정의하고, 하위클래스가 해당
메소드를 재정의 하는 것

⑷ 객체지향 설계원칙(SOLID)

■ 단일 책임 원칙(SRP, Single responsibility principle)
- 한 클래스는 하나의 책임만을 가져야한다.

개방 폐쇄 원칙(OCP, Open-closed principle)
- 확장에는 열려 있고, 수정에는 닫혀 있어야 한다.
- 기존의 코드를 변경하지 않으면서(Closed), 기능을 추가할 수 있도록(Open) 설계

리스코프 치환 원칙(LSP, Liskov substitution principle)
- 자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있어야 한다.
- 부모 클래스가 들어갈 자리에 자식 클래스를 넣어도 계획대로 작동해야 한다.

인터페이스 분리 원칙(ISP, Interface Segregation Principle)
- 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다.
- 자신이 사용하지 않는 인터페이스 때문에 영향을 받아서는 안 된다.

의존성 역전 원칙(DIP, Dependency Inversion Principle)
- 의존 관계를 맺을 때 자주 변화하는 것보다, 변화가 거의 없는 것에 의존해야 한다.
- 구체적인 클래스보다 인터페이스나 추상 클래스와 의존 관계를 맺어야 한다.

2. 디자인패턴

⑴ 디자인 패턴(Design Pattern) 개념

- 객체 지향 프로그래밍 설계를 할 때 자주 발생하는 문제들에 대해 재사용할 수 있도록 만들어놓은 패턴들의
모음
- 이미 만들어져서 잘 되는 것을 활용하여 재사용함으로써 프로그램 최적화에 도움을 준다.
- 효율적인 코드를 만들기 위한 방법론

⑵ 디자인 패턴 구조

■ 패턴의 이름과 유형
- 패턴을 부를 때 사용하는 이름과 패턴의 유형
문제 및 배경
- 패턴이 사용되는 분야 또는 배경, 해결하는 문제
솔루션
- 패턴을 이루는 요소들, 관계, 협동 과정
결과
- 패턴을 사용하면 얻게 되는 이점과 영향
사례
- 간단한 적용사례
샘플 코드
- 패턴이 적용된 원시코드

⑶ GoF 디자인 패턴

■ GoF(Gang of Four) 의 디자인 패턴
- 에리히 감마(Erich Gamma), 리차드 헬름(Richard Helm), 랄프 존슨(Ralph Johnson), 존 블리시디스(John Vissides) 에 의해 개발 영역에서 디자인 패턴을 구체화 하고 체계화 시킴
- 23가지의 디자인 패턴을 정리
- 각각의 디자인 패턴을 생성(Creational), 구조(Structural), 행위(Behavioral) 3가지로 분류

Gof 디자인 패턴 분류
- 객체 생성과 관련한 패턴
생성 패턴
- 객체 생성에 있어서 프로그램 구조에 영향을 크게 주지 않는 유연성 제공
구조 패턴
- 클래스나 객체를 조합해서 더 큰 구조를 만드는 패턴
행위 패턴
- 객체나 클래스 사이의 알고리즘이나 책임 분배에 관련된 패턴

생성(Creational) 패턴
구조(Structural) 패턴
행위(Behavioral) 패턴
- Chain of Responsibility
- Command
- Adapter
- Interpreter
- Abstract Factory
- Bridge
- Iterator
- Builder
- Composite
- Mediator
- Factory Method
- Decorator
- Memento
- Prototype
- Facade
- Observer
- Singleton
- Flyweight
- State
- Proxy
- Strategy
- Template Method
- Visitor

⑷ 디자인 패턴 종류

① 생성패턴
추상 팩토리(Abstract Factory)
- 구체적인 클래스에 의존하지 않고 서로 연관되거나 의존적인 객체들의 조합을 만드는 인터페이스를 제공하는
패턴
- 클라이언트 입장에서 실제 구현 클래스를 알 필요 없이 인터페이스만으로 시스템을 조작할 수 있도록 한다.

- 객체가 생성되거나 구성, 표현되는 방식과 무관하게 시스템을 독립적으로 만들 수 있게 도와준다.

빌더(Builder)
- 복합 객체의 생성과 표현을 분리하여 동일한 생성 절차에서도 다른 표현 결과를 만들어낼 수 있음
- 개체를 생성하는 과정의 약속과 구체적인 알고리즘 구현을 분리
new User.Builder(10)
.name("이흥직")
.password("1234")
.age(43)
.build();

팩토리 메소드(Factory Method)
- 객체 생성 처리를 서브 클래스로 분리해 처리하도록 캡슐화하는 패턴
- 객체의 생성 코드를 별도의 클래스/메서드로 분리함으로써 객체 생성의 변화에 대비하는 데 유용하다.

- 상위클래스에서 객체를 생성하는 인터페이스를 정의하고, 하위클래스에서 인스턴스를 생성하도록 하는 방식
- Virtual-Constructor 패턴이라고도 함

프로토타입(Prototype)
- 원본 객체를 복사함으로써 객체를 생성함
- prototype을 먼저 생성하고 인스턴스를 복제하여 사용하는 구조
- java의 clone()을 이용하여 생성하고자 하는 객체에 clone에 대한 Override를 해준다.

싱글톤(Singleton)
- 어떤 클래스의 인스턴스는 하나임을 보장하고 어디서든 참조할 수 있도록 함
public class CarClass{
private static CarClass car = new CarClass(); // 자신의 객체를 바로 생성
private CarClass(){} // 생성자가 private 이기 때문에 외부에서 접근 불가
public static CarClass getInstance(){
return car;
}
}

② 구조 패턴
어댑터(Adapter)
- 클래스의 인터페이스를 다른 인터페이스로 변환하여 다른 클래스가 이용할 수 있도록 함
- 인터페이스 호환성이 맞지 않아 같이 쓸 수 없는 클래스를 연관 관계로 연결해서 사용할 수 있게 해주는 패턴
- 클래스의 인터페이스를 사용자가 기대하는 다른 인터페이스로 변환하는 패턴
- 관련성이 없거나 예측하지 못한 클래스들과 협동하는 재사용 가능한 클래스를 생성할 때 사용한다.

브리지(Bridge)
- 구현부에서 추상층을 분리하여 각자 독립적으로 변형할 수 있게 하는 패턴
interface Shape{
public void draw();
}
class CircleShape implements Shape{
public void draw(){
printf(“Circle”);
}
}
class SquareShapeimplements Shape{
public void draw(){
printf(“Square”);
}
}

컴포지트(Composite)
- 객체들의 관계를 트리 구조로 구성하여 복합 객체와 단일 객체를 구분없이 다룸

데코레이터(Decorator)
- 주어진 상황 및 용도에 따라 어떤 객체에 다른 객체를 덧붙이는 방식
- 객체의 결합 을 통해 기능을 동적으로 유연하게 확장 할 수 있게 해주는 패턴
- 기능 확장이 필요할 때 서브 클래싱(subclassing) 대신 쓸 수 있는 유연한 대안을 제공한다.

- 상속을 사용하지 않고도 객체의 기능을 동적으로 확장할 수 있도록 해준다.
- 어떤 객체에 책임(responsibility)을 동적으로 추가 할 수 있도록 한다.

퍼사드(Facade)
- 서브시스템에 있는 인터페이스 집합에 대해 하나의 통합된 인터페이스(Wrapper) 제공
- 서브시스템 사이의 의사소통 및 종속성을 최소화하기 위하여 단순화된 하나의 인터페이스를 제공하는 패턴
- 서브시스템의 가장 앞쪽에 위치하면서 서브시스템에 있는 객체들을 사용할 수 있는 역할을 하는 패턴

플라이웨이트(Flyweight)
- 크기가 작은 여러 개의 객체를 매번 생성하지 않고 가능한 한 공유할 수 있도록 하여 메모리를 절약함
- 많은 수의 객체를 생성해야 할 때 사용하는 패턴

프록시(Proxy)
- 접근이 어려운 객체로의 접근을 제어하기 위해 객체의 Surrogate(대리)나 Placeholder(대체글)를 제공
- 객체를 직접 참조하지 않고, 객체를 대행하는 객체를 통해 접근 하는 방식

③ 행위 패턴
역할 사슬 패턴(Chain of Responsibility), 책임 연쇄
- 요청을 받는 객체를 연쇄적으로 묶어 요청을 처리하는 객체를 만날 때까지 객체 Chain을 따라 요청을 전달함
- 여러 개의 객체 중에서 어떤 것이 요구를 처리할 수 있는지를 사전에 알 수 없을 때 사용한다.
- 자신이 처리할 수 없는 경우 다음 객체에게 문제를 넘기게 된다.

커맨드(Command)
- Client가 보낸 요청을 객체로 캡슐화하여 이를 나중에 이용할 수 있도록 필요한 정보를 저장, 로깅, 취소할
수 있게 하는 패턴
- 요청을 객체로 감싸서 관리하는 패턴

인터프리터(Interpreter)
- 일련의 규칙으로 정의된 문법적 언어를 해석하는 패턴
- 간단한 언어의 문법을 정의하고 해석하는 패턴

반복자(Iterator)
- 내부를 노출하지 않고 내부에 들어있는 모든 항목에 접근할 수 있게 해 주는 방법을 제공해 주는 패턴
- 집합 객체의 요소들에 대해 순서대로 접근하는 방법을 제공한다.

- 배열(Array), 배열리스트(ArrayList), 해시 테이블과 같은 객체를 처리하는 데 사용하는 패턴
- 서로 다른 집합 객체 구조에 대해 동일한 방법으로 순회할 수 있다.

중재자(Mediator)
- 클래스 간의 복잡한 관계들을 캡슐화하여 하나의 클래스에서 관리하도록 처리하는 패턴
- 여러 객체들 사이에 중재자를 추가하여 중재자가 모든 객체들의 통신을 담당하도록 하는 패턴
- 객체간의 통제와 지시의 역할을 하는 중재자를 두어 객체지향의 목표를 달성하게 해준다.

메멘토(Memento)
- 객체의 상태 정보를 저장하고 사용자의 필요에 의하여 원하는 시점의 데이터를 복원 할 수 있는 패턴
- 캡슐화를 위반하지 않고 객체의 이전 상태를 저장하고 복원할 수 있는 디자인 패턴

옵저버(Observer)
- 객체의 상태 변화를 관찰하는 옵저버들의 목록을 객체에 등록하여 상태 변화시 각 옵저버에게 통지하는 패턴
- 어떤 객체의 상태가 변할 때 그 객체에 의존성을 가진 다른 객체들이 그 변화를 통지받고 자동으로 갱신될 수 있게 하는 패턴
- 일대 다의 객체 의존 관계를 정의하며, 한 객체의 상태가 변화되었을 때, 의존 관계에 있는 다른 객체들에게
자동적으로 변화를 통지하고 변경 시킨다.

상태(State)
- 객체의 상태에 따라 동일한 동작을 다르게 처리해야할 때 사용

전략(Strategy)
- 실행 중에 알고리즘을 선택할 수 있게 하는 패턴
- 특정한 계열의 알고리즘들을 정의하고 각 알고리즘을 캡슐화하며 이 알고리즘들을 해당 계열 안에서 상호
교체가 가능하게 만든다.
- 특정 컨텍스트에서 알고리즘을 별도로 분리하는 설계 방법
- 예) GPS 신호를 수신하는 경우와 수신하지 못하는 경우에 따라 차량의 위치를 구하는 다른 알고리즘을 선택
하고자 할 때 가장 적합한 설계 패턴

템플릿 메소드(Template Method)
- 특정 작업을 처리하는 일부분을 서브 클래스로 캡슐화하여 전체적인 구조는 바꾸지 않으면서 특정 단계에서
수행하는 내용을 바꾸는 패턴
- 알고리즘의 구조는 그대로 유지하면서 서브클래스에서 특정 단계를 재정의 할 수 있다.

방문자(Visitor)
- 실제 로직을 가지고 있는 객체(Visitor)가 로직을 적용할 객체를 방문하면서 실행하는 패턴
- 알고리즘을 객체 구조에서 분리시키는 디자인 패턴
- 객체지향 원칙(SOLID) 중 하나인 개방-폐쇄 원칙(Open-Closed Principle, OCP)을 적용하는 방법