Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Holub on-patterns-2-1

1,041 views

Published on

Published in: Technology, Health & Medicine
  • Be the first to comment

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 />

×