Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
1
OObjectbject--OOrientedriented DDesignesign
for for AgileAgile Software DevelopmentSoftware Development
작 성 자 : 고형호
메 일 : [email protected]
홈 페 이 지 : http://www.innosigmainnosigma.com
최종 수정일 : 2008.06.27
Second StorySecond Story 1.1.
http
://w
ww
.inn
osig
ma.
com
2
GoalGoal
ObjectObject--Oriented Design PrinciplesOriented Design Principles
http
://w
ww
.inn
osig
ma.
com
3
Contents
Part 1. ModelingPart 1. Modeling
Part 2. Part 2. AbstractAbstractionion
1. Single Responsibility Principle
2. Dependency Inversion Principle
3. Interface Segregation Principle
5. Open-Closed Principle
4. Liskov Substitution Principle
Part 3. Part 3. ObjectObject--Oriented Design PrinciplesOriented Design Principles
Part 4. Design PatternsPart 4. Design Patterns
4
1. Modeling
http
://w
ww
.inn
osig
ma.
com
5
Modeling
ModelingModeling
Modeling은 Model을 만들어 테스트 해보는 과정을 이야기 한다.
Model
AbstractionAbstraction Programming
Read World System
Test
Model은 어떤 것이 실제로도 잘 동작하는지 알아보려고 만드는 것이다.
목적 : 실제 물건을 만드는 것보다 훨씬 적은 비용으로 설계가 제대로 되었는지 판단할 수 있다.
6
2. Abstraction
http
://w
ww
.inn
osig
ma.
com
7
Abstraction
Model
Abstraction
Read World
어떻게어떻게 추상화를추상화를 할까할까??
1. Encapsulation(Information Hiding)
3. Polymorphism
2. Inheritance
2.1 Interface Inheritance
2.2 Implementation Inheritance
http
://w
ww
.inn
osig
ma.
com
8
Abstraction(cont.)
왜왜? ? 추상화는추상화는 어려운가어려운가??
Abstraction Level
High
Model
Abstraction
Read World
Encapsulation, Inheritance, Polymorphism
http
://w
ww
.inn
osig
ma.
com
9
Abstraction(cont.)
Abstraction Level
High
어떻게어떻게 추상화를추상화를 쉽게쉽게 할할 수수 있을까있을까??
Model
Abstraction
Read World
Design Patterns/Design Design Patterns/Design TemplateTemplate
ObjectObject--Oriented Design PrinciplesOriented Design Principles(SRP, DIP, LSP, ISP, OCP)(SRP, DIP, LSP, ISP, OCP)
Encapsulation, Inheritance, Polymorphism
10
3. Object-Oriented Design Principles
http
://w
ww
.inn
osig
ma.
com
11
Object-Oriented Design Principles
1. 단일 책임의 원칙(SRP, Single Responsibility Principle)
2. 의존 관계 역전의 원칙(DIP, Dependency Inversion Principle)
3. 인터페이스 분리의 원칙(ISP, Interface Segregation Principle)
4. 리스코프 대체 원칙(LSP, Liskov Substitution Principle)
5. 개발 폐쇄 원칙(OCP, Open-Closed Principle)
http
://w
ww
.inn
osig
ma.
com
12
Single Responsibility Principle
SRP
+ ResponsibilityA1()
+ ResponsibilityA2()
+ ResponsibilityB1()
+ ResponsibilityB2()
Service
책임 A
책임 B
클래스는 하나의 책임만을 맡아야 한다.
-. 클래스가 2가지 이상의 책임을 맡고 있으므로 응집도가 낮아 진다.
1. Single Responsibility Principle 필요성
2. Single Responsibility Principle 결과
-. 높은 응집도와 낮은 결합도를 지킬 수 있도록 한다.(응집도, Cohesion: 하나의 클래스가 하나의 책임(기능)을 온전히 순도 높게 담당하고 있는 정도)(결합도, Coupling: 클래스간의 서로 다른 책임들이 얽혀 있어서 상호 의존도가 높은 정도)
∴ 클래스 : 책임(클래스를 변경 시키는 이유) = 1 : N
+ ResponsibilityA1()
+ ResponsibilityA2()
ServiceA
책임 A+ ResponsibilityB1()
+ ResponsibilityB2()
ServiceB
책임 B
∴ 클래스 : 책임(클래스를 변경 시키는 이유) = 1 : 1
http
://w
ww
.inn
osig
ma.
com
13
Single Responsibility Principle(cont.)
+ Insert()
+ Update()
+ Delete()
+ GetExemption()
+ IsFlaggedForAudit()
+ GetTaxableEarnings()
Person
DB 접근 책임
Biz 로직 책임
SRP
Example.Example.
∴ 클래스 : 책임(클래스를 변경 시키는 이유) = 1 : 2
+ Insert()+ Update()+ Delete()
PersonDAO
DB 접근 책임+ GetExemption()+ IsFlaggedForAudit()+ GetTaxableEarnings()
Person
Biz 로직 책임
∴ 클래스 : 책임(클래스를 변경 시키는 이유) = 1 : 1
http
://w
ww
.inn
osig
ma.
com
14
Dependency Inversion Principle
Policy
Utility
Policy
Utility
하위 수준의 모듈(구체 클래스)
클라이언트는 구체 클래스가 아닌 인터페이스(추상 클래스)에 의존해야 한다.
Client
<<interface>>Service
인터페이스 소유권
인터페이스 소유권
상위 수준의 모듈(재사용 가능한 상위 수준 정책)
인터페이스
ConcreteService
DIP
의존성
의존성
-. 의존성: 상위 수준의 모듈은 하위 수준의 모듈에 의존하므로 상위 수준의 모듈은 하위 수준의 모듈에 대한 변경의 영향을 받는다.-. 인터페이스 소유권: 상위 수준의 모듈이 포함된 라이브러리는 하위 수준의 모듈이 포함된 라이브러리에 대한 변경의 영향을 받는다.
1. Dependency Inversion Principle 필요성
2. Dependency Inversion Principle 결과-. 의존성 역전: 상위 수준의 모듈은 인터페이스에 의존하므로 상위 수준의 모듈은 하위 수준의 모듈에 대한 변경의 영향을 받지 않는다.-. 인터페이스 소유권 역전: 상위 수준의 모듈이 포함된 라이브러리는 하위 수준의 모듈이 포함된 라이브러리에 대한 변경의 영향을 받지 않는다.
인터페이스
하위 수준의 모듈(구체 클래스)
<<interface>>ServiceClient
ConcreteService
상위 수준의 모듈(재사용 가능한 상위 수준 정책)
http
://w
ww
.inn
osig
ma.
com
15
Dependency Inversion Principle(cont.)
UtilityExample.Example.
DIP
+ Sort()
<<interface>>Sort
QuickSort
+ Sort()
인터페이스
하위 수준의 모듈(구체 클래스)
Policy
Client상위 수준의 모듈(재사용 가능한 상위 수준 정책)
∴ 상위 수준의 모듈은 하위 수준의 모듈/라이브러리에 대한
변경의 영향을받는다.
Policy
+ Sort()
<<interface>>Sort
QuickSort
+ Sort()
인터페이스
하위 수준의 모듈(구체 클래스)
Client상위 수준의 모듈(재사용 가능한 상위 수준 정책)
∴ 상위 수준의 모듈은 하위 수준의 모듈/라이브러리에 대한
변경의 영향을받지 않는다.
Utility
http
://w
ww
.inn
osig
ma.
com
16
Interface Segregation Principle
+ ClientGroupA
+ ClientGroupB
클라이언트는 특화된 여러 개의 인터페이스가 하나의 범용 인터페이스보다 낫다.
∴ 인터페이스 : 역할(클라이언트 그룹) = 1 : N
ISP
∴ 인터페이스 : 역할(클라이언트 그룹) = 1 : 1
-. 클라이언트는 자신이 사용하지 않는 메소드에 의존한다. -. 클라이언트는 자신이 사용하지 않는 메소드의 변화에 영향을 받는다.
1. Interface Segregation Principle 필요성
2. Interface Segregation Principle 결과-. 클라이언트는 자신이 사용하지 않는 메소드에 의존하지 않는다.-. 클라이언트는 자신이 사용하지 않는 메소드의 변화에 영향을 받지 않는다.
역할 A
역할 B책임
인터페이스 : 역할(클라이언트 그룹) = 1 : N
인터페이스 : 역할(클라이언트 그룹) = 1 : 1
...
...
(‘역할 A” 메소드만을 사용한다)
클라이언트 그룹 A
(‘역할 B’ 메소드만을 사용한다)
클라이언트 그룹 B
<<interface>>ServiceClientA
+ClientGroupA
<<interface>>ServiceClientB
+ClientGroupB
Service
Inheritance
ClientA ClientB
... ...
Delegation
<<interface>>ServiceClientA
+ ClientGroupA
<<interface>>ServiceClientB
+ ClientGroupB
ServiceServiceAdapter
<<delegation>>
ClientA ClientB
... ...
ClientA
ClientB
<<interface>>Service
http
://w
ww
.inn
osig
ma.
com
17
Interface Segregation Principle(cont.)
Example.Example.
+ SetSelectXxx()
+ GetSelectXxx()
+ SetScrollXxx()
+ GetScrollXxx()
SelectClient
ScrollClient
<<interface>>Table
Select 역할
Scroll 역할Scroll 클라이언트 그룹
Select 클라이언트 그룹
∴ 인터페이스 : 역할(클라이언트 그룹) = 1 : 2
ISP
<<interface>>SelectTable
+ SetSelectXxx()+ GetSelecXxx()
<<interface>>ScrollTable
+ SetScrollXxx()+ GetScrollXxx()
Service
Inheritance
ClientA ClientB
Delegation
<<interface>>SelectTable
+ SetSelectXxx()+ GetSelectXxx()
<<interface>>ScrollTable
+ SetScrollXxx()+ GetScrollXxx()
ServiceSelectAdapter
<<delegation>>
ClientA ClientB
∴ 인터페이스 : 역할(클라이언트 그룹) = 1 : 1
http
://w
ww
.inn
osig
ma.
com
18
Liskov Substitution Principle
기반 클래스는 파생 클래스로 대체할 수 있어야 한다..
+ DoCommonSomething()+ DoSomething()
+ DoCommonSomething()+ DoSomething()
LSP
-. 파생 클래스에서 기반 클래스의 모든 메소드를 지원(메소드가 던지는 예외까지 포함)하지 않으면 ‘IS-A’ 관계가 성립하지 않는다.-. 다형성은 ‘IS-A’ 관계를 기반으로 하므로 안정적인 다형성 획득을 힘들게 한다(잠재적인 OCP 위반).
1. Liskov Substitution Principle 필요성
2. Liskov Substitution Principle 결과-. 파생 클래스는 기반 클래스의 모든 메소드를 지원한다(올바른 ‘IS-A’ 관계 구성).-. 올바른 ‘IS-A’ 관계를 기반으로 안정적인 다형성 획득을 할 수 있다(OCP 준수).
Client
clsss Client{
public void DoService(Service service){
// 불안정한 다형성 획득service.DoSomething();
}}
ConcreteService
clsss ConcreteService : Service {
public void DoCommonSomething(){
// do common something ...}public void DoSomething(){
throw new UnsupportedOperationException();}
}
∴ 예외 처리로 인하여 기반 클래스의 메소드를 지원하지 않는다.
<<interface>>NewService
+ DoCommonSomething()+ DoSomething()
Service
+ DoCommonSomething()
+ DoCommonSomething()
Client
clsss Client{
public void DoService(NewService service){
// 안정적인 다형성 획득service.DoCommonSomething();
}}
ConcreteService
<<interface>>Service
http
://w
ww
.inn
osig
ma.
com
19
Liskov Substitution Principle(cont.)
Example.Example.
LSP
+ Add(Object) : int+ Remove(int)+ Clear()
+ Push(Object)+ Pop() : Object
ArrayList
Stack
Stack stack = new Stack();stack.Push("1");stack.Push("2");stack.Clear(); // 더 이상 올바르게 데이터를 관리할 수 없게 된다. stack.Push(“3”);
IS-A 관계: A stack is an array.
∴ Stack/ArrayList 계층 구조는취약하다(기반 클래스는 파생 클래스로 대체할 수 없다).
+ Push(Object)+ Pop() : Object
Stack
+ Add(Object) : int+ Remove(int)+ Clear()
ArrayList
Stack stack = new Stack();stack.Push("1");stack.Push("2");stack.Clear(); // 컴파일 에러 발생.stack.Push(“3”);
IS-A 관계: A stack is not an array.
http
://w
ww
.inn
osig
ma.
com
20
Open-Closed Principle
확장에는 열러 있어야 하고, 변경에는 닫혀 있어야 한다.
+ DoSomething(o : Object)
Service+ DoConcrete()
ConcreteServiceA
+ DoConcrete()
ConcreteServiceB
clsss Service{
public void DoSomething(Object o){
if (o is ConcreteServiceA){
((ConcreteServiceA)o).DoConcrete();}else if (os is ConcreteServiceB){
((ConcreteServiceB)o).DoConcrete();}
}}
clsss Service{
public void DoSomething(ServiceImpl impl){
impl.DoConcrete();}
}
OCP
-. 모듈(Service)는 구체 클래스(ConcreteServiceA/B)에 의존하므로 구체 클래스의 내부 변경에 영향을 받는다.-. 모듈(Service)는 새롭게 추가(확장)되는 구체 클래스를 소스 코드 수정 없이는 인지할 수 없다.
1. Open-Closed Principle 필요성
2. Open-Closed Principle 결과-. 모듈(Service)는 추상화(ServiceImpl)에 의존하므로 구체 클래스(ConcreteServiceA/B)의 내부 변경에 영향을 받지 않는다.-. 모듈(Service)는 새롭게 추가(확장)되는 구체 클래스를 소스 코드 수정 없이 인지할 수 있다.
변경의 확산을 막아 주고 확장의 포인트가 된다.
+ DoSomething(impl : ServiceImpl)
Service
+ DoConcrete()
<<interface>>ServiceImpl
+ DoConcrete()
ConcreteServiceB
+ DoConcrete()
ConcreteServiceA
http
://w
ww
.inn
osig
ma.
com
21
Open-Closed Principle(cont.)
Example.Example.
Client
ConcreteServiceA
OCP
ConcreteServiceB
clsss Client{
public void DoSomething(Object o){
if (o is ConcreteServiceA){
((ConcreteServiceA)o).DoXxx();}else if (os is ConcreteServiceB){
((ConcreteServiceB)o).DoXxx();}
}}
∴ Client는 기존 구체 클래스의 내부 변경에 영향을 받는다.또한, 새롭게 추가(확장)되는 구체 클래스를 소스 코드 수정 없이는 인지할 수 없다.
... 새롭게 추가되는 구체 클래스들
기존 구체 클래스들의 내부 변경
Client <<interface>>Service
...ConcreteServiceA
clsss Service{
public void DoSomething(Service service){
service.DoXxx();}
}∴ Client는 기존 구체 클래스의 내부 변경에 영향을 받지 않는다.
또한, 새롭게 추가(확장)되는 구체 클래스를 소스 코드 수정 없이는 인지할 수 있다.
22
4. Design Patterns
http
://w
ww
.inn
osig
ma.
com
23
DIP
Design Patterns
+ TemplateMethod()
- PrimitiveOperator1()
- PrimitiveOperator2()
AbstractClass
- PrimitiveOperator1()
- PrimitiveOperator2()
ConcreteClass
Template Method
SRP
OCP(LSP) OCP(LSP)
+ AlgorithmInterface()
<<interface>>Strategy
+ AlgorithmInterface()
ConcreteStrategy
+ ContextInterface()
Context
Strategy
SRP SRP