no source is source · 2015-01-21 · no source is good source abstract factory pattern 작성자:...
TRANSCRIPT
NO source is GOOD sourceAbstract Factory Pattern
작 성 자 : 고형호
이 메 일 : [email protected]
최초 작성일 : 2006.01.19
최종 수정일 : 2006.01.26
파일 버전 : v06
요구사항 구현 시나리오요구사항 구현 시나리오(1/3) – 기본 소스
요구사항 구현 시나리오(2/3) – 차트 추가 생성
요구사항 구현 시나리오(2/3) – 정리
목 차
첫째, 문제 해결하기첫째, 문제 해결하기(1/2) - 목적
첫째, 문제 해결하기(2/2) - 방법
첫째, 문제 해결 시나리오 – 변경의 국지화/정보 은닉
둘째, 문제 해결하기둘째, 문제 해결하기(1/2) - 목적
둘째, 문제 해결하기(2/2) - 방법
둘째, 문제 해결 시나리오둘째, 문제 해결 시나리오(1/5) – 변경의 국지화
둘째, 문제 해결 시나리오(2/5) – 다형성
둘째, 문제 해결 시나리오(3/5) – 결합도
둘째, 문제 해결 시나리오(4/5) – 소스 정리
둘째, 문제 해결 시나리오(5/5) – UML 정리
클래스 디자인 원칙
Abstract Factory Pattern 의도
Abstract Factory Pattern 정리
COPQ(Cost of Poor Quality)
Axis* CreateAxis(int nType){
switch(nType) {case LINE_CHART :
return new LineAxis;...}
}
Legend* CreateLegend(int nType){
switch(nType) {case LINE_CHART :
return new LineLegend;...}
}
...
위와 같이 함수와 분기문을 이용하여 객체를 생성하는 함수를 구현 하였다.
만약, 추가 요구사항이 발생되어 새로운 차트을 추가 생성해야 된다면
어떻게 구현 할 것인가?
class Axis{public:
virtual ~ChartAxis() = 0;};
class Legend{public:
virtual ~ChartLegend() = 0;};
class LineAxis : public Axis { ... };class LineLegend : public Legend { ... }
요구사항 구현 시나리오(1/3) – 기본 소스
Axis* CreateAxis(int nType){
switch(nType) {case LINE_CHART :
return new LineAxis;
...}
}
Legend* CreateLegend(int nType){
switch(nType) {case LINE_CHART :
return new LineLegend;
...}
}
...
논리적으로는 단순히 새로운 차트가 추가 생성 되었지만
물리적으로는 관련 함수(CreateAxis, CreateLegend)를 찾아 수정 하였다.
case BAR_CHART :return new BarAxis; CreateAxis 함수 수정
case BAR_CHART :return new BarLegend; CreateLegend 함수 수정
즉, 논리적인 면과 물리적인 면이 불일치와 관련 함수를 찾아 수정해야 한다.
요구사항 구현 시나리오(2/3) – 차트 추가 생성
원인은
논리적인 면과 물리적인 면이 불일치와 관련 함수를 찾아 수정해야 하는...
결과는
즉, 다형성(Polymorphism)을 적용하지 못 한다.
즉, 정보 은닉(Information Hiding)이 약하다.
요구사항 구현 시나리오(3/3) - 정리
- 관련 함수가 프로그램 전체에 퍼져 있다.
- 분기문으로 인해 새롭게 추가된 사항을 반영하기 어렵다.
새로운 조건을 반영하기 위해서는 기존 소스의 분석이나 수정이 필요하다.
즉, 프로그램 전체를 다시 개발하는 것과 비슷한 노력이나 비용이 들 수 있다.
첫째, 문제 해결하기
관련 함수를 찾아 수정해야 한다.
---------------> Next << 계획하고 시작하자! >>
목적은
관련 함수를 찾아 수정해야 하는 문제 해결 ...
첫째, 문제 해결하기(1/2) - 목적
변경 가능성이 있는 관련 함수들을 한 곳으로 모은다.
방법은
관련 함수를 찾아 수정해야 하는 문제 해결 ...
첫째, 문제 해결하기(2/2) - 방법
- 변경의 국지화(Localization of Change)
변경이 예상되는 부분을 국지화 시킴으로써 변경에 소요되는 비용을
최소화 한다.
- 정보 은닉(Information Hiding)
변경의 국지화를 위해 변경될 가능성이 많은 부분을 클래스 내부로
숨기어 해당 클래스 내부만 변경시켜주어 변경 대상폭을 줄인다.
Axis* CreateAxis(int nType){
switch(nType) {...}
}
Legned* CreateLegend(int nType){
switch(nType) {...}
}
변경의 국지화(Localization of Change)생성과 관련하여 변경 가능성이 많은 함수들을 클래스 한 곳으로 모은다.
정보 은닉(Information Hiding)변경될 가능성이 많은 부분은 클래스 내부로 숨기어 해당 클래스 내부만 변경시켜 변경 대상폭을 줄인다.
수정 전
class ChartFactory{
Axis* CreateAxis(int nType){
switch(nType) {...}
}
Legend* CreateLegend(int nType){
switch(nType) {...}
}...
};
수정 후
첫째, 문제 해결 시나리오 – 변경의 국지화/정보 은닉
둘째, 문제 해결하기
논리적인 면과 물리적인 면이 불일치 한다.
---------------> Next << 계획하고 시작하자! >>
목적은
논리적인 면과 물리적인 면이 불일치의 문제 해결 ...
둘째, 문제 해결하기(1/2) - 목적
- 생성될 객체가 바꾸더라도 클라이언트는 아무런 변경할 필요가 없다.
- 독립적인 다양한 차트를 추가 생성할 수 있다.
방법은
논리적인 면과 물리적인 면이 불일치의 문제 해결 ...
- 변경의 국지화(Localization of Change)
변경이 예상되는 부분을 국지화 시킴으로써 변경에 소요되는 비용을
최소화 한다.
- 다형성(Polymorphism)을 적용하자.
기존의 것과는 독립된 새로운 것을 추가, 확장은 인터페이스를 이용한
클래스 상속이다.
- 결합도(Coupling) 를 감소 시키자.
다양한 차트 각각을 하나의 클래스로 캡슐화하여 추가 가능 하도록 한다.
둘째, 문제 해결하기(2/2) - 방법
class Chart{
Axis* CreateAxis(int nType){
switch(nType) {case LINE_CHART :
return new LineChart;...}
}...
};
수정 전
class ChartFactory{
ChartAxis* CreateAxis() = 0; …
};
수정 후
변경의 국지화(Localization of Change)CreateAxis 함수를 인터페이스로 정의하여 다형성으로 다양한 새로운 차트를
추가 생성할 수 있도록 한다.
둘째, 문제 해결 시나리오(1/5) – 변경의 국지화
다형성(Polymorphism)을 적용하자.
인터페이스(추상클래스)를 통해서만 참조하면서 구체적인 구현은 다형성에 따라
결정되도록 한다.
class Chart{
Axis* CreateAxis(int nType){
switch(nType) {case LINE_CHART :
return new LineAixs;...}
}...
};
수정 전
int main(){
ChartFactory* pFactory = NULL;...Axis* pAxis = pFactory->CreateAxis();...
}
class ChartFactory{
virtual Axis* CreateAxis() = 0; …
};
수정 후
둘째, 문제 해결 시나리오(2/5) – 다형성
class Chart{
Axis* CreateAxis(int nType){
switch(nType) {case LINE_CHART :
return new LineAxis;case BAR_CHART :
return new BarAxis;...}
}...
};
수정 전
class ChartFactory{
virtual ChartAxis* CreateAxis() = 0; ...
};
class LineFactory : public ChartFactory{
virtual ChartAxis* CreateAxis() { new LineAxis; }...
};
class BarFactory : public ChartFactory{
virtual ChartAxis* CreateAxis() { new BarAxis; }...
}
수정 후
결합도(Coupling) 를 감소 시키자.
다양한 차트 각각을 하나의 클래스로 캡슐화하여 추가 가능 하도록 한다.
둘째, 문제 해결 시나리오(3/5) – 결합도
class ChartFactory{public:
virtual Axis* CreateAxis() = 0;virtual Legend* CreateLegend() = 0;
};
class LineFactory : public ChartFactory{public:
virtual Axis* CreateAxis(){
return new LineAxis;}
virtual Legend* CreateLegend(){
return new LineLegend;}
};
int main(){
ChartFactory* pFactory;...Axis* pAxis = pFactory->CreateAxis(); Legend* pLegend = pFactory->CreateLegend();…
}
class BarFactory : public ChartFactory{
virtual Axis* CreateAxis() { … };virtual Legend* CreateLegend() { … };
};해당 차트만 추가로 구현하면 된다!
클래스 디자인으로 국지화, 다형성, 결합도 를 반영한 소스코드.
추가 요구사항이 발생되어 새로운 차트가 추가생성 된다면
둘째, 문제 해결 시나리오(4/5) – 소스 정리
ClientChartFactory
+CreateAxis()+CreateLegend()
BarFactory
+CreateAxis()+CreateLegend()
LineFactory
+CreateAxis()+CreateLegend()
Axis
LineAxis BarAxis
Legend
LineLegend BarLegend
ChartFactory pFactory = new LineFactory;Axis* pAxis = pFactory->CreateAxis();Legend* pLegend = pFactory->CreateLegend();
둘째, 문제 해결 시나리오(5/5) – UML 정리
클래스 디자인 원칙
의존성 뒤집기 원칙(Dependency Inversion Principle)
추상화된 것에 의존하라.
구상 클래스(Concrete classes)에 의존하지 않도록 한다.
출처: Head First Design Patterns
클래스 디자인 원칙
의존성 뒤집기 원칙을 위한 가이드라인
- 어떤 변수에도 구상 클래스에 대한 레퍼런스를 저장하지 맙시다.: 의존적인 코드를 미리 방지하기 위함.
- 구상 클래스에서 유도된 클래스를 만들지 맙시다.: 특정 클래스에 의존하게 되므로.
- 베이스 클래스에 이미 구현되어 있던 메소드를 오버라이드 하지 맙시다.: 베이스 클래스가 제대로 추상화된 것이 아니었다고 볼 수 있다.
출처: Head First Design Patterns
상세화된 서브클래스를 정의하지 않고도
서로 관련성이 있거나 독립적인 여러 객체군을 생성하기 위한
인터페이스를 제공한다.
출처 : GoF의 Design Patterns
Abstract Factory Pattern 의도
ClientAbstractFactory
+CreateProductA()+CreateProductB()
ConcreteFactory1
+CreateProductA()+CreateProductB()
ConcreteFactory2
+CreateProductA()+CreateProductB()
AbstractProduct A
ProductA2 ProductA1
AbstractProduct B
ProductB2 ProductB1
Abstract Factory Pattern 정리
장점은
- 구체적인 클래스를 분리한다.
- 제품군을 쉽게 대체할 수 있도록 한다.
- 제품 간의 일관성을 증진한다.
단점은
- 새로운 종류의 제품을 제공하기
어렵다.
즉, COPQ는 모든 활동이 불량이나 결함 없이 완벽하게 수행된다면 사라지게 될 비용입니다.
p.s. 우리는 오늘도 결함이 많은 클래스 디자인으로 아침,점심,저녁,저녁,저녁(눈에 보이지 않는)으로
개발하고 있다(?). 완벽하지 못한 클래스 디자인으로 개발함으로써 지불하는 대가는 아닐까.
COPQ(Cost of Poof Quality)
COPQ(저품질 비용)은
눈에 보이는 비용매출의 4 ~ 6%
눈에 보이지 않는 비용
회계상 파악 불가능(Lost Opportunity) 매출의 25 ~ 35%
이미지 저하
매출 기회 손실
재설계 비용
고객의 신뢰 상실, ...
재작업품질 보증, ...
숨겨진 품질비용(Hidden Factory)
반품
납기 지연
기업의 모든 업무에서 낮은 품질로 인해 발생하는 비용을 의미한다.
저품질 비용은 재작업, 검사 등의 눈에 보이는 비용 및 이미지 저하,
매출 기회 손실, 재설계 비용 등의 눈에 보이지 않는 비용을 포함한다.
출처 : 서비스 이노베이션 엔진, 6시그마
Abstract Factory Pattern……..
Design Patterns
참고 도서1. GoF 디자인 패턴! 이렇게 활용한다.2. GoF 디자인 패턴
3. Head First Design Patterns