Holub on-patterns-2-1

957 views
884 views

Published on

Published in: Technology, Health & Medicine
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
957
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
11
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Holub on-patterns-2-1

  1. 1. 인터페이스로 프로그래밍하기그리고 몇 개의 생성패턴(1/2)<br />아꿈사<br />10.06.19<br />임정환<br />
  2. 2. 왜 extends가 나쁜가?<br />extend는 OO언어에서 중요한 기능을 차지<br />따라서 extend를 쓴다면 뭔가 OO적인 것을 하고 있구나~ 하고 생각하면서 여기저기 막 쓰는 게 문제(그러나 이 extends는 부작용이 참 많다)<br />객체 지향이란! 동일한 타입에 다양한 구현을 제공하는 다형성(기반 클래스의 행동을 이를 상속한 클래스에서 재정의 하는 것)이 객체 지향 사고의 핵심!<br />이런 다형성은 extends 보다는 implements(인터페이스)를 통해 가장 잘 성취할 수 있음!(앞으로 계속 설명할 것임)<br />
  3. 3. 인터페이스 vs클래스<br />구현 상속보단 인터페이스 상속이 훨씬 바람직<br />유연성의 상실<br />구현 상속이 나쁜이유는베이스 클래스의 함수가 이미 구현되어 있기 때문에 이 구현에 종속적일 수 밖에 없기 때문!<br />결과적으로 수정이 힘듬!<br />애자일 개발 방법론의 핵심중 하나는 디자인과 개발을 병행! 완벽한 요구 사항 도출 이전에 프로그래밍 시작.. 즉 자주 고쳐야 된다는 사실! 유연한 프로그램이 아니라면 병행 개발은 불가능!<br />
  4. 4. 인터페이스 vs클래스(예제1)<br />void f()<br />{<br />LinkedList list = new LinkedList();<br /> //...<br /> modify(list);<br />}<br />void modify(LinkedList list)<br />{<br />list.add(...);<br />doSomethingWith(list);<br />}<br />옵빠!.. LinkedList즐이에요.. HastSet으로 바꿔주세요 님하…<br />
  5. 5. 인터페이스 vs클래스(예제1)<br />void f()<br />{<br />LinkedList list = new LinkedList();<br /> //...<br /> modify(list);<br />}<br />void modify(LinkedList list)<br />{<br />list.add(...);<br />doSomethingWith(list);<br />}<br />고쳐야 할 곳이 점점 는다.<br />
  6. 6. 인터페이스 vs클래스(예제1)<br />void f()<br />{<br /> Collection list = new LinkedList();<br /> //...<br /> modify(list);<br />}<br />void modify(Collection list)<br />{<br />list.add(...);<br />doSomethingWith(list);<br />}<br />
  7. 7. 인터페이스 vs클래스(예제1)<br />void f()<br />{<br /> Collection list = new Hashset();<br /> //...<br /> modify(list);<br />}<br />void modify(Collection list)<br />{<br />list.add(...);<br />doSomethingWith(list);<br />}<br />한 곳만 바꾸면 된다.<br />
  8. 8. 인터페이스 vs클래스(예제2)<br />f()<br />{<br /> Collection c = new Hashset();<br /> //...<br /> examine(c);<br />}<br />void examine(Collection c)<br />{<br /> for(Iteratori = c.iterator(); i.hasNext();)<br /> //i.next() 통해 원소를 순회<br />}<br />f()<br />{<br /> Collection c = new Hashset();<br /> //...<br /> examine(c.iterator());<br />}<br />void examine(Iteratori)<br />{<br /> for(; i.hasNext();)<br /> //i.next()를 통해 원소를 순회<br />}<br />Iterator를 받기 때문에 Collection으로는 처리못하는Map도 처리 가능<br />Iterator를 오버라이딩하여 다르게 순회하는 기능 가능<br />일반화된 버전은 수정없이 이러한 모든 변화가 수용가능!!<br />유연하구나!!<br />
  9. 9. 결합도<br />결합이 없는 프로그램이란 존재하지 않지만…..<br />프로그램에서 코드간의 결합도가 낮을수록 좋다.<br />전역 변수가 나쁜이유!(강한 결합)<br />전역 변수의 타입을 바꾼다고 생각햇을때 이 변수를 사용하는 모든 코드를 검사,수정,제테스트해야함<br />
  10. 10. 결합도<br />OO 개념을 충실히 지키면 결합도를 줄일 수 있다..<br />상수를 제외한 모든 필드는 private로!<br />get, set은 줄여라..(public이나 진배없음)<br />나중에 유지보수시 편리함<br />
  11. 11. 깨지기 쉬운 기반 클래스 문제<br />구현 상속은 자식과 부모 클래스간 강한 결합을 의미<br />부모를 조금 수정했음에도 자식이 망가질 수 있음<br />
  12. 12. 깨지기 쉬운 기반 클래스 문제(예제) <br />class Stack extends ArrayList<br />{<br /> private inttopOfStack = 0;<br /> public void push(Object article)<br /> {<br /> add(topOfStack++, article);<br /> }<br /> public Object pop()<br /> {<br /> return remove(--topOfStack);<br /> }<br /> public void pushMany(Object[] articles)<br /> {<br /> for(inti =0; i < articles.length; ++i)<br /> push(articles[i]);<br /> }<br />}<br />//스택의현재 위치를 저장하는 topOfStack를 정의함<br />Stack aStack = new Stack();<br />aStack.push("1");<br />aStack.push("2");<br />aStack.clear(); //clear는 ArrayList Method<br />대략 낭패.. topOfStack은 0이 안됨<br />개망..!<br />상속을 하게 되면 원하지 않던 메소드clear() 까지 모두 상속하게 됨<br />
  13. 13. 깨지기 쉬운 기반 클래스 문제(예제)<br />ArrayList를 상속한 것 자체가 개념적으로 말이안됨<br />Stack is ArrayList가 아니다..<br />어떻게 고칠까?<br />Clear()에서 예외를 던저버리자!<br />이건 컴파일 에러를 런타임 에러로 옮겨 버리는 망할 놈의 생각<br />topOfStack대신 size()메소드 이용<br />이건 clear()만 어떻게 고쳐보겠다는생각<br />다른 함수에서 개망…. (ex. removeRange..)<br />지금 상황에서 상속은 어폐가 있다..상속대신 합성을 이용하자!!!<br />
  14. 14. 깨지기 쉬운 기반 클래스 문제(예제)<br />class Stack<br />{<br />private inttopOfStack = 0;<br />private ArrayListtheData = new ArrayList();<br />public void push(Object article)<br />{<br />theData.add(topOfStack++, article);<br />}<br />public Object pop()<br />{<br /> return theData.remove(--topOfStack);<br />}<br />public void pushMany(Object[] articles)<br />{<br />for(inti =0; i < articles.length;++i)<br /> push(articles[i]);<br />}<br />public int size()<br />{<br /> return theData.size();<br />}<br />}<br />상속하지 않고 ArrayList를 이용하여 구현하였다.<br />이제 ArrayList가 수정되는 일이 생겨도 개망하는 일은 없어짐!<br />변경에 강해짐~<br />
  15. 15. 깨지기 쉬운 기반 클래스 문제(예제)<br />class MonitorableStack extends Stack<br />{<br />private inthighWaterMark = 0;<br />private intlowWaterMark = 0;<br />public void push(Object o)<br />{<br />push(o);<br />if(size() > highWaterMark)<br />highWaterMark = size();<br />}<br />public Object pop()<br />{<br />Object poppedItem = pop();<br />if(size() < lowWaterMark)<br />lowWaterMark=size();<br />return poppedItem;<br />}<br />public intmaximumSize(){return highWaterMark;}<br />public intminimumSize(){return lowWaterMark;}<br />public void resetMarks(){highWaterMark=lowWaterMark=size();}<br />}<br />}<br />85~86쪽 예제인데, Stack을 또다시 구현 상속하는 MonitorableStack에 대해 애기하고 있음..<br />앞에 경우처럼 pushMany에서 또 개망하는 일이 발생됨..!<br />이와 같은 이유는 기본적으로 구현상속이란 개념이 Base Class에 뭔가 구현이 되어 있는데 구현자의 의도와는 다르게 베이스 클래스의 함수가 동작할 수 있기 때문임..<br />정리하면.. 구현상속 쓰지마! 깜빡했다간오동작한다구!!<br />
  16. 16. 깨지기 쉬운 기반 클래스 문제(예제)<br />구현 상속은 문제가 많다. 왠만하면인터페이스 상속을 사용하라!<br />상속된 기능이 없기 때문에 잘못될 일도없다<br />인터페이스 상속을 사용하면 안전하게 다형성 획득!<br />구현 상속은 필요한 기능이지만 위험하기 때문에 사용하기 전에 충분히 심사숙고 필!<br />물론 인터페이스 상속은 일일히 다 만들어줘야 하기 때문에 코딩이 느는 단점이 있기는 하다.<br />하지만 오동작하는 것보다 낫다…! (이클립스를 사용하면 쉽게 위임 메소드를 만들 수 있다고 함)<br />그러나 이렇게 말하는 자 있도다…<br />난 기반 클래스 수정할 때마다 파생 클래스는 다 검토를 하기 때문에 문제 없다구!!!<br />이미 당신은 기반 클래스를 확장하는 것이 아니라 인터페이스 구현을 하고 있소이다… 걍 인터페이스 구현을 하시오.<br />
  17. 17. 깨지기 쉬운 기반 클래스 문제(예제)<br />앞에서 설명한 Stack, MonitorableStack정답은…<br />죄송합니다… 타이핑이 넘 많아서…. 88,89쪽을 펴주세요..<br />Interface로 Stack 만듭니다.<br />SimpleStack은 implements를 통해 구현함<br />SimpleStack은 ArrayList를 사용하여 기능을 구현 - 위임(합성)<br />MonitorableStack은역시 implements를 통해 구현<br />MonitorableStack은 SimpleList를 사용하여 기능을 구현 – 위임(합성)<br />
  18. 18. 다중 상속<br />다중 상속이 유용할 때도 있는데 역시 구현 상속보다는 캡슐화(합성)을 이용하라~<br />
  19. 19. 프레임워크<br />MFC를 잘근잘근 씹고 있는데….<br />MFC가 널리 사용됬기 때문에 마소의 방식은 올바른 거야라고많이들 생각하고 있음<br />MFC는 기본적으로 구현 상속 기반이다.<br />View, document를 상속해서 쓰고 있음..<br />역시. 개망의 지름길…<br />또한 뭔가 기능을 변경하고 싶으면 상속 기반은 클래스를 상속해서 만들어야 되는데 이렇게 되면 클래스가 엄청늘어나게 되고 클래스가 늘어나면 늘수록 개발기간은 길어진다.<br />
  20. 20. 지금까지 구현상속의 폐혜를 보셨습니다. 이제 본격적으로 패턴을 보아요.. 하지만<br />여기서도 구현 상속의 폐혜를설명하기 위해 패턴을 예로 듭니다.<br />Template Method 패턴<br />Factory Method 패턴(애가 문제임)<br />
  21. 21. Template Method 패턴<br />Template Method 패턴<br />기반 클래스 코드가 오버라이딩 가능한 메소드를 호출하고 메소드의 구현은 기반 클래스를 구현 상속한 클래스에 제공하는..<br />저자도 이디엄과 패턴의 경계가 모호한 정도의 패턴이라고 함 <br />패턴 참 쉽죠잉..~~?<br />
  22. 22. Factory Method 패턴<br />Factory Method 패턴은 기반 클래스에 알려지지 않은 구체 클래스를 생성하는 Template Method라 할 수 있다.<br />사실 코드 보고 이해하는 데 정말 어려웠음;; <br />Factory Method 패턴은 아주 유연하지만(기능 수정 추가가 쉽다)필요 이상으로 복잡하다. 이 복잡함이 유지 보수성과 사용 편의성을 크게 해침..<br />책에 예제는 너무 복잡하여 다른 예제를 준비<br />인용 : http://underclub.tistory.com/125<br />
  23. 23. Factory Method 패턴<br />Product는 Factory Method 패턴을 사용하여 생성할 부모클래스<br />IDCard는 실제 생성되는 자식 클래스<br />Factory는 Product를 생성을 담당하는 클래스<br />IDCardFactory는 실제 기능을 가진 자식 Product를 생성하는 클래스<br />
  24. 24. Factory Method 패턴<br />Use 함수가 product마다의 고유 기능을 담당<br />Create는 public에 final로 객체생성은 저 함수로 담당<br />Createproduct와 registerproduct는 생성해줄 때객체마다 다른 기능을 부여해줄 수 있음(abstract)<br />
  25. 25. Factory Method 패턴<br />Factory Method 패턴의 문제점<br />뭔가 패턴을 사용하기 위해 extends를 사용하고 있다는 냄새다.<br />Product 를 상속해서 IDCard를 만들고 있는데 이는 Factory에서 사용하기 위해 이런 구조로 만들었다. Extends가 필요해서 한것인 아니라!!!;;<br />Factory Method 패턴은 extends 관계를 잘못 사용하고 있다.!! 대안은 있다. Strategy 패턴이 멋진 대안이 될 수 있다.(전 모른다는 … 담에 설명 좀 잘…부탁 ㅎ)<br />실제 사용<br />IDCardFactory를 만들고<br />Create 함수로 생성<br />Use 함수로 사용<br />
  26. 26. 깨지기 쉬운 기반 클래스 문제 정리<br />꼼수를 쓰지말고, 구현 상속 대신 캡슐화(합성)와 인터페이스를 사용하라!<br />앞으로 설명할 패턴 중 상당수가 구현 상속을 인터페이스 상속으로 바꾸는 방법에 대한 내용<br />추상화를 잘하라.. 추상화를 잘하면 유연해짐(수정이 쉬워짐), 하지만 복잡성을 증가함.유연성과 복잡성 사이에서 적절한 트레이드 오프를 하라~<br />지금까지 한 말들을 정리한 챕터임..<br />
  27. 27. 언제 extends를 사용해도 좋은가?<br />클래스 정규화<br />클래스의 중복되는 기능을 제거하는 경우<br />구현 상속을 사용하지 않는다면 파생 클래스에서 동일한 코드를 반복해야 함<br />여기서는 구현하고자 하는 프로그램이 런타임에 객체들이 서로 어떻게 메시지를 주고 받는 지에 대한 ‘동적모델’을 규명한 후!에 각 클래스가 사용하는 공통적인 기능이 파악이 된다면 그 때! extends를 사용하라고 함!<br />수행되는 연산이 공유될 때<br />Is- a 관계가 클래스 계층 구조를 검증하는 데 효율적이지 못함<br />Manager is a Employee 라고 할때 과연 Manager Extends Employee 인가….<br />Employee와 Manager가 같은 일을 할 수도<br />전혀 다른일을 할 수도<br />Manager가 Employee가 하는 일까지 총괄해서 할 수도<br />결론 : 자연어에 휘둘리지 말고, 수행되는 연산의 공유에 초점을 맞추어라!<br />컴파일 타임 타입 검사<br />컴파일 타임에 타입 검사를 해야할 경우가 있다.<br />물론 타입검사를 하지않고Implements를 사용하는 쪽으로 구현할 수도 있다.<br />복잡도를 분석한 후 단순한 것을 사용하자<br />
  28. 28. 결론<br />extends(구현 상속)왠만하면 쓰지마..<br />extends 써야 한다면 기능에 맞게 잘 써..<br />Factory Method처럼 쓸려면 쓰지마…<br />
  29. 29. 캄사합니다….<br />질문은 사절~ C++ 촙오에요..<br />

×