4 3 Observer object object Subject Observer notify
4. 3 디자인 패턴 – Observer 패턴 감시 object와 피감시 object간의 효율적인 메시지 패턴 Subject Observer notify() attach(Observer) detach(Observer) update() Observer observer. update() Concrete. Subject Concrete. Observer subject. State return subject. State set. State() get. State() observer. State Subject update() observer. State = subject. get. State()
4. 3 디자인 패턴 – Observer 패턴의 클래스간 시퀀스 다이어그램 : Concrete. Subject a: Concrete. Observer b: Concrete. Observer attatch(this) detatch(this) : Concrete. Subject set. State() : Concrete. Observer 1 : notify() 1. 1 : update() 1. 1. 1 : get. State()
4. 3 디자인 패턴 – State 패턴 종업원 직종 직종 급여계산() Request() public class 종업원{ private money 급여; private char 직종; public void set. State(char s) { 직종 = s } public void 급여계산(void){ if(직종==‘ 1’) this. 급여 = 기본급()+성과급(); else if(직종==‘ 2’) this. 급여 = 기본급()+자격수당(); else this. 급여 = 기본급(); } private money 기본급() {…}; private money 성과급() {…}; } 직종 * state 급여계산() public class 종업원{ private money 급여; private 직종 state; 영업직형 급여계산() public void set. State(직종 s) { this. state = s } 기술직형 급여계산() public void Request(void){ this. 급여 = this. state. 급여계산(); } } public abstract class 직종 {…} public class 영업직형 extends 직종{ public money 급여계산(){ return 기본급 + 성과급(); } private money 성과급() {…}; }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 사례 : 비디오 대여점의 대여관리 시스템 Member Rental member. Type : int get. Member. Type() * work. State : int date. Rented : Date rental. Period : int rental. Fee : int work. State : int set. Rental. Fee() calc. Rental. Fee. VIP() get. Work. State() category * Video get. Video. Title() 구현결과 회원타입이 VIP, ORDINARY 요구사항 VIP를 Gold, Silver 로 구분 *
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 Member Video. Title Rental member. Type : int get. Member. Type() * work. State : int date. Rented : Date rental. Period : int rental. Fee : int work. State : int set. Rental. Fee() calc. Rental. Fee. VIP() get. Work. State() category Video * * get. Video. Title() public class Member{ private String member. Name; private int member. Type; static final int ORDINARY = 0; static final int VIP = 1; Public class Rental{ private Member member; static final int ORDINARY = 0; static final int VIP = 1; private int rental. Fee; Rental(Member member, Video video, Date date. Rented, int rental. Period){ set. Member(member); set. Video(video); … set. Rental. Fee(); } Member(String member. Name, int member. Type){ this. member. Name = member. Name; this. member. Type = member. Type; } public int get. Member. Type(){ return this. member. Type; } public void set. Rental. Fee(){ switch(this. member. get. Member. Type()){ case ORDINARY: this. rental. Fee = calc. Rental. Fee(this); break; case VIP: this. rental. Fee = calc. Rental. Fee(this); break; } } … } }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 Member Video. Title Rental member. Type : int get. Member. Type() * work. State : int date. Rented : Date rental. Period : int rental. Fee : int work. State : int set. Rental. Fee() calc. Rental. Fee. VIP() get. Work. State() category Video * * get. Video. Title() public class Member{ private String member. Name; private int member. Type; static final int ORDINARY = 0; static final int VIP = 1; Public class Rental{ private Member member; static final int ORDINARY = 0; static final int VIP = 1; private int rental. Fee; Rental(Member member, Video video, Date date. Rented, int rental. Period){ set. Member(member); set. Video(video); … set. Rental. Fee(); } Member(String member. Name, int member. Type){ this. member. Name = member. Name; this. member. Type = member. Type; } public int get. Member. Type(){ return this. member. Type; } public void set. Rental. Fee(){ switch(this. member. get. Member. Type()){ case ORDINARY: this. rental. Fee = calc. Rental. Fee(this); break; case VIP: this. rental. Fee = calc. Rental. Fee(this); break; } } … } 나쁜 냄새 발견 }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 Member. Type member. Type : int get. Member. Type() Ordinary VIP member. Type : int get. Member. Type()
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • State 패턴의 적용 1. 타입 코드의 캡슐화 public class Member{ private String member. Name; private int member. Type; static final int ORDINARY = 0; static final int VIP = 1; Member(String member. Name, int member. Type){ this. member. Name = member. Name; this. member. Type = member. Type; } public class Member{ private String member. Name; private int member. Type; static final int ORDINARY = 0; static final int VIP = 1; Member(String member. Name, int member. Type){ this. member. Name = member. Name; set. Member. Type(member. Type); } public int get. Member. Type(){ return this. member. Type; } public void set. Member. Type(int member. Type){ this. member. Type = member. Type; } } public int get. Member. Type(){ return this. member. Type; } }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • State 패턴의 적용 2. 상태클래스 생성, 명명 3. 타입 코드에 서브 클래스 추가 4. 상태 클래스에 추상 get 메소드 생성, 상태 서브 클래스에 오버 라이딩한 get 메소드로 반환 abstract class Member. Type{ abstract int get. Member. Type. Code(); } public class Member{ private String member. Name; private int member. Type; static final int ORDINARY = 0; static final int VIP = 1; … class Ordinary extends Member. Type{ int get. Member. Type. Code() { return Member. ORDINARY; } } class VIP extends Member. Type{ int get. Member. Type. Code() { return Member. VIP; } } } 5. 컴파일
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • State 패턴의 적용 6. 호출 클래스에 상태 클래스 참조 필드 준비 7. 원 get메소드 변경, 새로운 상태 서브 클래스에 위임 public class Member{ private String member. Name; private int member. Type; static final int ORDINARY = 0; static final int VIP = 1; } public class Member{ private Member. Type member. Type; static final int ORDINARY = 0; static final int VIP = 1; … int get. Member. Type(){ return this. member. Type. get. Member. Type. Code(); } public int get. Member. Type(){ return this. member. Type; } … }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • State 패턴의 적용 8. 원 클래스의 set메소드를 상태 서브 클래스의 오브젝트 대입 public class Member{ … … public void set. Member. Type(int member. Type){ switch(member. Type){ case ORDINARY: this. member. Type = new Ordinary(); break; case VIP: this. member. Type = new VIP(); break; default: throw new Illegal. Argument. Exception(“invalid”); break; } } public void set. Member. Type(int member. Type){ this. member. Type = member. Type; } … } 9. 컴파일 및 테스트
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • 나쁜 냄새 발견 public class Member{ … public void set. Member. Type(int member. Type){ switch(member. Type){ case ORDINARY: this. member. Type = new Ordinary(); break; case VIP: this. member. Type = new VIP(); break; default: throw new Illegal. Argument. Exception(“invalid”); } } 나쁜냄새 - switch 문 사용 è이것은 필요한 구조이고, è변경요구가 있어도 큰 문제가 되지 않고, è이곳에만 존재하므로 괜찮다. … }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • 나쁜 냄새 발견 정의코드의 중복 - 참조처 변경 ‘회원 타입을 어떻게 표현할 것인가’의 정의코드가 중복됨 public class Member{ private String member. Name; private Member. Type member. Type; static final int ORDINARY = 0; static final int VIP = 1; … } Public class Rental{ private Member member; static final int ORDINARY = 0; static final int VIP = 1; … } public class Member{ private String member. Name; private Member. Type member. Type; … } Public class Rental{ private Member member; … } abstract class Member. Type{ static final int ORDINARY = 0; static final int VIP = 1; abstract int get. Member. Type. Code(); }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • 나쁜 냄새 발견 정의코드의 중복 - 참조처 변경 ‘회원 타입을 어떻게 표현할 것인가’의 정의코드가 중복됨 public class Member{ private String member. Name; private Member. Type member. Type; … public void set. Member. Type(int member. Type) { this. member. Type = member. Type; } } abstract class Member. Type{ static final int ORDINARY = 0; static final int VIP = 1; abstract int get. Member. Type. Code(); } class Ordinary extends Member. Type{ int get. Member. Type. Code(){ return Member. ORDINARY; } } class VIP extends Member. Type{ int get. Member. Type. Code(){ return Member. VIP; } } ? public class Member{ private String member. Name; private Member. Type member. Type; … void set. Member. Type(int member. Type) { this. member. Type = Member. Type. new. Member. Type(member. Type); } } abstract class Member. Type{ static final int ORDINARY = 0; static final int VIP = 1; static Member. Type new. Member. Type(int member. Type){ switch(member. Type){ case ORDINARY: return new Ordinary(); case VIP: return new VIP(); default: throw new Illegal. Argument. Exception(“Invalid”); } } abstract int get. Member. Type. Code(); }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • 나쁜 냄새 발견 정의코드의 중복 - 참조처 변경 Public class Rental{ private Member member; static final int ORDINARY = 0; static final int VIP = 1; Public class Rental{ private Member member; private int rental. Fee; Rental(Member member, Video video, Date date. Rented, int rental. Period) { … } public void set. Rental. Fee(){ switch(this. member. get. Member. Type()){ case ORDINARY: this. rental. Fee = calc. Rental. Fee(this); break; case VIP: this. rental. Fee = calc. Rental. Fee(this); break; } } … } public void set. Rental. Fee(){ switch(this. member. get. Member. Type()){ case Member. Type. ORDINARY: this. rental. Fee = calc. Rental. Fee(this); break; case Member. Type. VIP: this. rental. Fee = calc. Rental. Fee(this); break; } } … }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • 두번째 나쁜 냄새 발견 Public class Rental{ private Member member; private int rental. Fee; Rental(Member member, Video video, Date date. Rented, int rental. Period) { … } 나쁜냄새 - switch 문 사용 public void set. Rental. Fee(){ switch(this. member. get. Member. Type()){ case Member. Type. ORDINARY: this. rental. Fee = calc. Rental. Fee(this); break; case Member. Type. VIP: this. rental. Fee = calc. Rental. Fee(this); break; } } … Ø회원타입이 증가할 때 마다 코드 변경 필요 Ø코드의 중복이 발생 }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • 두번째 나쁜 냄새 제거 폴리모피즘에 의한 조건기술의 변환 Public class Rental{ private Member member; private int rental. Fee; Rental(Member member, Video video, Date date. Rented, int rental. Period) { … } 대여료 계산을 이동시킴 Rental Ordinary, VIP public void set. Rental. Fee(){ switch(this. member. get. Member. Type()){ case Member. Type. ORDINARY: this. rental. Fee = calc. Rental. Fee(this); break; case Member. Type. VIP: this. rental. Fee = calc. Rental. Fee(this); break; } } … }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • 두번째 나쁜 냄새 제거 폴리모피즘에 의한 조건기술의 변환 Public class Rental{ private Member member; private int rental. Fee; Rental(Member member, Video video, Date date. Rented, int rental. Period) { … } public void set. Rental. Fee(){ switch(this. member. get. Member. Type()){ case Member. Type. ORDINARY: this. rental. Fee = calc. Rental. Fee(this); break; case Member. Type. VIP: this. rental. Fee = calc. Rental. Fee(this); break; } } … } Public class Rental{ private Member member; private int rental. Fee; Rental(Member member, Video video, Date date. Rented, int rental. Period) { … } public void set. Rental. Fee(){ this. rental. Fee = this. member. calc. Rental. Fee(this); } … } public class Member{ private String member. Name; private Member. Type member. Type; … int calc. Rental. Fee(Rental rental){ return this. member. Type. calc. Rental. Fee(rental); } }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • 두번째 나쁜 냄새 제거 폴리모피즘에 의한 조건기술의 변환 abstract class Member. Type{ static final int ORDINARY = 0; static final int VIP = 1; static Member. Type new. Member. Type(int member. Type){ switch(member. Type){ case ORDINARY: return new Ordinary(); case VIP: return new VIP(); default: throw new Illegal. Argument. Exception(“Invalid”); } } abstract int get. Member. Type. Code(); abstract int calc. Rental. Fee(Rental rental); } class Ordinary extends Member. Type{ … int calc. Rental. Fee(Rental rental) { return ***? ***; } } class VIP extends Member. Type{ … int calc. Rental. Fee(Rental rental) { return ***? ***; } }
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • 리팩토링 후의 클래스 다이어그램 Ordinary VIP get. Member. Type. Code() calc. Rental. Fee() {abstract} member. Type Video. Title get. Work. State() get. Member. Type. Code() calc. Rental. Fee() category * * Member get. Member. Type() set. Member. Type() calc. Rental. Fee() Rental * date. Rented: Date rental. Fee: int set. Rental. Fee() Video * get. Video. Title()
4. 4 소프트웨어의 유연성을 높여주는 리팩토링 – 리팩토링의 실제 • GOLD, SILVER 추가 abstract class Member. Type{ static final int ORDINARY = 0; //static final int VIP = 1; static final int GOLD = 2; static final int SILVER = 3; static Member. Type new. Member. Type(int member. Type){ switch(member. Type){ case ORDINARY: return new Ordinary(); //case VIP: // return new VIP(); case GOLD: return new Gold(); case SILVER: return new Silver(); default: throw new Illegal. Argument. Exception(“Invalid”); } } abstract int get. Member. Type. Code(); abstract int calc. Rental. Fee(Rental rental); } class Ordinary extends Member. Type{ … int calc. Rental. Fee(Rental rental) { return ***? ***; } } //class VIP extends Member. Type{ // … //} class Gold extends Member. Type{ … } class Silver extends Member. Type{ … }
- Slides: 47