'2. Design'에 해당되는 글 20건
- 2017.02.18 Segment tree
- 2017.01.31 Counting sort
- 2014.12.04 Inversion Of Control (= Hollywood Principle)
- 2014.07.15 Free wireframing set for powerpoint
- 2014.01.06 Create MySQL ERD using ERWin
- 2012.05.04 Dropbox 웹 사이트
- 2012.05.04 변수와 가독성
- 2012.02.19 아이디와 패스워드
- 2011.11.21 사용자의 정신 모델에 따라...
- 2011.10.22 임상 실험
- 2011.10.18 애플 수석 디자이너 - 조나단 아이브
- 2011.10.18 SOLID (Object-oriented design)
- 2009.10.13 두 개의 모자
- 2009.10.13 Refactoring 의 목적 1
- 2009.10.13 Switch 문
- 2009.07.07 Scriptable COM Object 설계 시 고려해야 할 점
- 2009.02.17 The Open-Closed Principle
- 2008.10.06 GOF 디자인 패턴 (생성 패턴)
- 2008.08.19 정보 은닉의 가치
- 2008.06.15 Strategy 패턴 소스 (셀 정렬 알고리즘 포함) 1
Inversion Of Control (= Hollywood Principle)

Simply it means,
"Don't call us, we'll call you."
In case of the library, you would call its API but, A framework would call your implementation. In addition, a framework would control to create and destroy an object instead of you.
Template method which is one of the GOF patterns is very related to this.
- Helpful sites:
Free wireframing set for powerpoint

Source : http://designmodo.com/windows-8-wireframe/
The wireframing set is available as a .pptx file that you can download using the link below:
It is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
Screen shots:
windows-8-wireframing-set.zip.pptx
Visit the following site to get more detail:
가끔 Dropbox 를 방문할 때마다 웹사이트의 간결함에 무척이나 놀란것 같습니다.
처음에 방문하면 단지 아래 화면만 보여주고,
"Download Dropbox" 라는 버튼을 누르면 아래처럼 정말 필요한 설명만 가지고 해당 서비스를 이용할 수 있게끔 해 줍니다.
아우, 정말 훌륭합니다!
출처: The Art of Readable Code (번역서: 읽기 좋은 코드가 좋은 코드다)
☞ 개발자 강추 서적입니다.
변수와 관련된 3가지 문제점들이 있으며,
1. The more variables there are, the harder it is to keep track of them all.
2. The bigger a variable’s scope, the longer you have to keep track of it.
3. The more often a variable changes, the harder it is to keep track of its current value.
이러한 이슈를 처리하는 방법은 다음과 같습니다.
Eliminate Variables
- Useless Temporary Variables
- Eliminating Intermediate Results
- Eliminating Control Flow Variables
Shrink(Reduce) the Scope of Variables
- Creating "Private" Variables
- Moving Definitions Down
- const or final
- immutable or permanent
<input type="text" id="input1" value="Dustin"> <input type="text" id="input2" value="Trevor"> <input type="text" id="input3" value=""> <input type="text" id="input4" value="Melissa"> ...
var setFirstEmptyInput = function (new_value) { var found = false; var i = 1; var elem = document.getElementById('input' + i); while (elem !== null) { if (elem.value === '') { found = true; break; } i++; elem = document.getElementById('input' + i); } if (found) elem.value = new_value; return elem; };
var setFirstEmptyInput = function (new_value) { var i = 1; var elem = document.getElementById('input' + i); while (elem !== null) { if (elem.value === '') { elem.value = new_value; return elem; } i++; elem = document.getElementById('input' + i); } return null; };
var setFirstEmptyInput = function (new_value) { for (var i = 1; true; i++) { var elem = document.getElementById('input' + i); if (elem === null) return null; // Search Failed. No empty input found. if (elem.value === '') { elem.value = new_value; return elem; } } };
개발자는 사용자가 아이디와 패스워드를 자유롭게 선택할 수 있도록 해야 합니다. 이는 사용자가 원할 경우 이메일 주소를 아이디로 사용할 수 있어야 함을 뜻하며, 이를 거부할 경우는 채찍으로 다스려야 합니다. 개발자는 사용자의 삶을 복잡하게 하기 위해 존재하는 것이 아닙니다. 그리고 은행과 같이 큰 돈을 지키고 있는 것이 아니라면, 사용자가 원하는 패스워드가 어떤 것이든 허용해야 합니다. 문자의 선택에 제한을 두면 안되고, 강력한 패스워드를 요구해서도 안됩니다. 그럼 사용자는 패스워드를 적어둘 것이고, 그러면 패스워드의 안전성은 포스트잇 수준으로 떨어지겠죠.
- 가끔 회원가입을 하려고 하면 이메일 주소에 '.' 과 같은 잘못된 문자가 있다고 하는 사이트가 더러 있습니다. 이런 경우 그냥 사이트에서 나가버리는 데 가끔 아주 유명한 사이트마저도 그렇게 하는 경우가 있습니다. ㅡㅡ;
- 소프트웨어, 누가 이렇게 개떡같이 만든 거야 - 中에서
(http://book.daum.net/detail/book.do?bookid=KOR9788991268395)
중에서 발췌한 내용입니다. (강추)
사이트 디자이너는 테스트 사용자에게 어떤 작업을 주어야 할지 모를 때도 종종 있습니다. 예를 들면 "7월에 탈라하시(Tallahassee)로 가는 항공편 중 가장 싼 티켓을 구매하시오."와 같이 실제 사용자가 사이트에 와서 하려는 일을 시키는 대신, "사이트에서 좋은 점과 나쁜 점을 알려주세요."와 같이 말하는 것을 본 적이 있습니다. 재어드 스풀은 Ikea.com 에서 수행했던 테스트에 대해 다음과 같이 설명합니다. 이케아의 디자이너들은 테스트 사용자들에게 "책장을 찾으시오."와 같은 작업을 시켰습니다. 거의 모든 테스트 사용자가 사이트의 검색창에 '책장'을 입력해 원하는 결과를 얻었습니다. 그러나 스풀이 "여러분은 200권 이상의 소설책을 소장하고 있으며 현재 상자에 담겨 거실 여기저기에 널브러져 있습니다. 어떻게 정리하는 게 좋을까요?"라고 테스트 사용자들에게 말했을 때, 그들은 매우 다르게 행동했습니다. 그들은 검색창을 사용하는 대신 상품 목록을 살펴보고, 가끔 검색 기능을 사용하기도 했지만 검색어는 '책장'이 아니라 '선반'이었습니다. 사용자들은 훨씬 더 어려워했는데, 그들의 정신 모델(mental model)이 사이트 디자이너와 매우 달랐기 때문입니다. 디자이너들이 이런 테스트를 하고 제3자에게 익숙하지 않은 질문을 던지게 할 정도로 똑똑하지 못했다면 이런 사실을 절대 깨닫지 못했을 것입니다. |
뭉뜽그려서 "일단 사용해 보시구 장점과 단점을 알려주세요" 보단 구체적인 기능, 사용성과 관련된 질문을 스스로에게, 테스터에게, 그리고 고객에게 할 수 있어야겠습니다.
조나단 아이브 (Jonathan ive)
- 이러한 제품에 관해서 가장 많이 노력했던 것은 바로 디자인을 멀리하는 것이었습니다. 저는 이러한 방법으로 만들어낸 형태야 말로 좀 더 객관적인 형태가 될 수 있다고 생각합니다. 느끼기에 이것이 필연적인 결과이고 디자인되지 않은 것처럼 보이고, 이것이 원래부터 이런 모습일 것이고, 어떻게 다른 모습일 수 있겠냐고 생각하겠지만 말이죠.
(어찌 이리도 멋진말을... 스마트폰 하면 아이폰 스타일... 이것 말고 어떻게 다른 모습일 수 있을까... 제가 느꼇던 바가 당신의 디자인이군요...ㅎㅎ)
Initial | Stands for (acronym) | Concept |
---|---|---|
S | SRP |
|
O | OCP |
|
L | LSP |
|
I | ISP |
|
D | DIP |
|
소프트웨어를 개발할 때, 아마 모자를 바꿔 쓰는 자신을 발견할 것이다. 새로운 기능을 추가하기 위해 시작했는데, 코드 구조가 바뀌면 작업이 더 쉬워진다는 것을 깨닫는다. 그래서 모자를 바꿔 쓰고, 한동안 리팩토링을 한다. 코드의 구조가 더 좋게 바뀌었으면, 다시 모자를 바꿔 쓰고 새로운 기능을 추가한다. 새로운 기능이 제대로 작동할 때, 새로운 기능에 대한 코드가 이해하기 힘들게 작성되었다는 것을 깨닫고는, 다시 모자를 바꿔 쓴 다음 리팩토링을 한다. 이 모든 작업을 하는데 단지 10분 정도 걸릴 뿐이지만, 그 시간 동안은 항상 자신이 어떤 모자를 쓰고 있는지 알고 있어야 한다.
출처 : Refactoring - 마틴 파울러
이것과 대조되는 좋은 예가 퍼포먼스 최적화이다. 리팩토링과 마찬가지로 퍼포먼스 최적화도 보통 동작을 바꾸지는 않는다 (속도는 빼고). 단지 내부 구조를 바꿀 뿐이다. 그러나 그 목적이 다르다. 퍼포먼스 최적화는 종종 코드를 이해하기 더 어렵게 만들지만, 필요한 퍼포먼스를 얻기 위해서는 그렇게 해야 한다.
둘째, 리팩토링은 겉으로 보이는 소프트웨어의 기능을 변경하지 않는다는 것이다. 리팩토링 후에도 소프트웨어는 여전히 동일한 기능만을 가지고 있다.
만일 리팩토링을 하다 while 루프의 실행이 늘어 났다고 하자. 시간이 오래걸리는 while 루프는 퍼포먼스를 나쁘게 한다. 많은 프로그래머는 이와 같은 단순한 이유로 이런 리팩토링을 하지 않으려 할지도 모른다. 그러나 단지 그럴지도 모른다는 말에 주목하라. 프로파일(profile)을 보기 전에는 계산을 위해 루프가 얼마나 많은 시간을 소모할 지, 또는 그 루프가 시스템의 전체 퍼포먼스에 영향을 줄 만큼 자주 호출될 지에 대해 알 수 없다. 이 while 리팩토링에 대해 걱정할 필요 없다. 만약 최적화를 하고 있다면 이 부분에 대해 걱정을 해야겠지만, 그렇지 않으면 이와 같이 리팩토링을 함으로써 최적화를 하기가 더 유리해 질 것이고, 최적화를 효과적으로 하기 위한 더 많은 옵션을 가지게 될 것이다.
출처 : Refactoring - 마틴 파울러
class Rental... double getCharge() { double result = 0; switch(getMovie().getPriceCode()) { case Movie.REGULAR: ... case Movie.NEW_RELEASE ... break; case Movie.CHILDREN: ... break; } return result; } |
위 코드를 보면 getCharge 메소드를 Movie 클래스로 옮겨야 함을 의미한다.
class Rental... double getCharge() { return _movie.getCharge(_daysRented); } |
그리고 _movie 에 추상 메소드와 상속을 이용한 다형성을 주어 구현하면 깔끔하게 switch 문을 제거할 수 있다.
출처 : Refactoring - 마틴 파울러
Eric's Complete Guide To Type Signatures Of Scriptable Object Models
: 이 글은 마지막에 링크된 주소의 글을 번역한 것이다. 번역이 미숙하더라도 이해바람.
내가 수년 동안 받은 많은 질문들에 대해서 소개한다.
"VBScript 와 JScript 둘 다에서 쉽게 호출될 수 있도록 하기 위해서는 어떻게 객체를 디자인 하는가?"
COM 은 매우 복잡한 타입 시스템을 정의하고 스크립트 엔진은 그 타입 시스템의 하위 집합만을 지원한다. C++ 에서 쉽게 호출될 수 있는 객체를 생성하는 것은 가능하지만 VB6, VBScript, 그리고 특별히 JScript 와 같은 다른 언어에서 쉽게 호출되지 않을 수 있다.
나는 여러번 개인적인 이슈에 대하여 블로그에 글을 올렸다; 지난달에 그에 관해 설명하는 문서를 요청 받았다. 뒤에 좀더 자세한 설명을 위한 메인 기사에 관한 링크를 제공할 것이다.
이것은 기본적으로 "해야할 것 들"에 대해서가 아니라 "하지 말아야 하는 것"에 대한 목록이다. 또한 직관적이고, 발견될 수 있는, 테스트 가능한, 문서화할 수 있는, 확장할 수 있는, 등등의 객체 모델을 디자인 하는 것에 관해 언급해야 할 것들이 굉장히 많이 더 존재한 다는 것을 기억하라. 언젠가 그것에 관해 이야기 할지도 모르지만, 오늘은 메소드 타입 원형의 구현자(the implementor of method type signatures) 가 반드시 피해야 하는 매우 기초적인 질문에 관해서만 언급할 것이다.
Numeric types
VBScript 는 VT_I2(short signed integer), VT_I4(long signed integer), VT_R4(single float), VT_R8(double float), VT_CY(currency), 그리고 VT_UI1(unsigned bye) 데이터에 대한 산술연산을 할 수 있다. 8-바이트 정수, unsigned integers, signed bytes 그리고 fixed-point decimals 는 지원되지 않는다.
대조적으로, Jscript 는 bytes, shorts, singles, currencies 그리고 unsigned integers 를 즉시 VT_I4 또는 VT_R8 중 하나로 (알맞은 것으로) 즉시 변환한다, 그리고 그것들을 가지고 연산을 수행한다.
일반적으로, 스크립트 엔진이 비록 특정 타입에 대한 연산을 지원하지 않더라고, 여전히 그 값을 저장하고 그것을 파라미터로 전달할 수 있다. (?: you can still store the value and pass it around.) 한 객체에서 VT_DECIMAL 값을 얻기 위한 “접착제(glue)”로서 스크립트를 사용할 수 있고 그것을 다른 객체에 전달한다.
만약 당신의 객체 모델이 fixed-point decimals(VT_DECIMAL)을 사용한다면, 스크립트에서 객체를 사용하는 것은 어려울 것이다. 거의 모든 floating point 산술 연산은 에러가 생긴다는 것을 기억하라. 당신의 객체 모델이 currencies 의 의존적이라면 Jscript 는 원하는 목적을 실패하게끔 할 수 있다. 원칙적으로는, double 과 long 만 지원한다.
좀더 많은 정보를 위해서는 아래 링크를 보라.
http://blogs.msdn.com/ericlippert/archive/2003/09/15/53000.aspx
Dates
VBScript 와 Jscript 는 날짜를 다룸에 있어 완전히 다른 코드를 사용한다. 두 시스템은 “좋았어(gotchas)”로 가득하다. 코드가 COM 에서 사용되는 표준 VT_DATE를 사용하여 date를 조작한다면, Jscript 는 그것들을 자동적으로 내부 date 포맷으로 변환할 것이다. 일반적으로 그것을 다루는 방법이 있긴 하지만, 그 코드는 약간 트릭키 할 수 있다.
자세한 정보는 아래를 보라.
http://blogs.msdn.com/ericlippert/archive/2003/09/16/53013.aspx
http://blogs.msdn.com/ericlippert/archive/2003/10/06/53150.aspx
Object Types
IDispatch 가 아닌 인터페이스를 노출하는 객체는 VBScript 나 Jscript 에서 사용될 수 없다. VT_UNKNOWN 을 넘긴다면, 즉시 그것을 VT_DISPATCH 로 변환하려고 시도한다. Scriptable 객체 모델은 전적으로 dispatchable 해야 한다.
비-디폴트(non-default) 디스패치 인터페이스는 나쁘다. Jscript 는 비-디폴트 디스패치를 지원하지 않는다. VBScript 는 하나가 주어진다면 비-디폴트 디스패치를 사용하긴 하지만, 디폴트 디스패치로부터 디스패치를 얻기 위한 어떠한 방법도 제공하지 않는다. 다중으로 분리된 디스패치 인터페이스를 지원하는 객체를 작성하지 말라.
자세한 정보는 아래를 보라.
http://blogs.msdn.com/ericlippert/archive/2003/10/10/53188.aspx
빠뜨린 인자, 빠뜨린 정보
VBScript 는 빠뜨린 인자를 지원한다. 메소드를 아래와 같이 호출 할 수 있다.
x = foo.bar(123, , 456)
그러면 VBScript 는 PARAMNOTFOUND 가 설정된 에러 필드를 가진 파라미터 VT_ERROR 를 넘길것이다. 그러고 나서는 Callee 가 그 문제를 다루는 책임이 있고, 그 인자를 알맞은 디폴트 값으로 채운다.
Jscript 는 빠뜨린 인자를 지원하지 않는다. 12개의 인자를 가지고 그들 중 일부는 빠뜨릴 수 있다고 예상하는 객체 모델은 Jscript 에서는 사용하기가 어렵다. (그리고 그들은 아마도 매우 나쁘게 설계된 메소드이다.)
Jscript 와 VBScript 모두 이름지어진 인수(named arguments)를 지원하지 않는다.
빠뜨린 인자를 전달하는 일반적인 대안은 VBScript 에서는 Nothing, Null, 또는 Empty 를 넘기는 것이고, Jscript 에서는 null 또는 undefined 를 넘기는 것이다. Null 과 null 은 VT_NULL 을 전달하고, Empty 와 undefined 는 VT_EMPTY 를 전달한다, 그리고 Nothing 은 디스패치 객체 포인터 값이 없는 VT_DISPATCH 를 전달한다. Jscript 에서 “null” 객체를 전달하는 쉬운 방법은 없다. 이것은 Jscript 의 디자인 결함이라고 생각한다, 하지만 우리는 현재 그것에서 벗어날 수 없다. 좋은 Scriptable 객체 모델의 설계자는 Jscript 에서 사용하는 것을 쉽게 하기 위해 Null 과 Nothing 을 동일하게 다루는 것을 고려할 수도 있다.
또 다른 관련 이슈는 “empty/null 문자열” 문제이다. C에서, 빈 문자열과 널 문자열은 다르게 처리된다. VB6, VBScript, 그리고 Jscript 는 그렇지 않다. 널 문자열과 빈 문자열은 동일하다는 규약을 사용한다. 하지만 VB는 이 규약을 사용하지 않는 Win32 API 를 호춣랄 수 있다, 그래서 VB6 과 VBScript 는 실행시에 빈 문자열 또는 널 문자열을 넘기는 것을 허용한다. Jscript 는 이 기능을 가지고 있지 않다.
널과 빈 문자열을 구분하는 Dispatchable COM 객체 모델은 거의 확실히 버그가 있다. 그렇게 하지 마라.
자세한 정보는 아래를 보라.
http://blogs.msdn.com/ericlippert/archive/2003/09/12/52976.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/30/53120.aspx
http://blogs.msdn.com/ericlippert/archive/2003/10/01/53128.aspx
More On Parameter Passing
“Out” 파라미터는 나쁘다. – 스크립트가능한 객체 모델에서는 out 파라미터를 가지는 메소드는 작성하지 마라. Jscript 는 out 파라미터를 전혀 지원하지 않는다. VBScript 경우에도 메모리 릭이 일어나는 시나리오가 있을 수 있다.
“In-out” 파라미터 역시 나쁘다.” – Jscript 는 in-out 파라미터를 전혀 지원하지 않는다. VBScript 는 항상 VT_VARIANT | VT_BYREF 를 넘긴다, 그리고 IDispatch::Invok 의 디폴트 구현은 만일 메소드가 hard-typed byref 파라미터를 예상하고 있다면 타입 불일치(type mismatch)를 일으킬 것이다. 고유한 강제적인 로직을 작성하거나 인자를 variant 로 만들수 있지만, 둘 다 트릭키 하다. 전적츠로 그것을 피하는 가장 좋은 방법은 – out 또는 in-out 파라미터를 사용하지 않는 것이다.
“Out-retval” 값은 사실상 파라미터가 아니다 – 그것은 반환값이다 – 그래서 out-retval 은 괜찮다.
자세한 정보는 아래를 보라.
http://blogs.msdn.com/ericlippert/archive/2003/09/15/52996.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/15/53005.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/15/53006.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/29/53117.aspx
Arrays
배열은 나쁘다. Jscript 는 VB-스타일의 배열에 대해 매우 빈약하게 지원한다. 다차원 vb스타일 배열은 Jscript 에서 처리하기가 특히 어렵다. 파라미터로 배열을 가지는 객체 모델을 작성하지 않으려고 노력하거나 배열을 반환하기만 하는 객체 모델을 작성하라. (이것은 큰 배열을 복사하는데 드는 성능 비용을 피할 수 잇기 때문에 역시 좋은 생각이다.)
VB6 는 foo(10 to 20, 4 to 6) 과 같은 임의의 인덱스 범위를 가진 배열을 생성할 수 있다. VBScript 는 그러한 배열을 사용할 수는 있지만 그것들을 생성할 수는 없다 – 모든 VBScript 는 0 에서 시작하는 배열을 생성한다.
스크립트 엔진은 variant 배열만 지원한다. 바이트의 배열은 underlying OS 에 의해 문자열로 변환될 수 있지만, 그것은 아주 엉망으로 만드는 것이다.
좀더 자세한 정보는 아래를 보라.
http://blogs.msdn.com/ericlippert/archive/2003/09/22/53061.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/22/53069.aspx
http://blogs.msdn.com/ericlippert/archive/2004/05/25/141525.aspx
Collections
VBScript 와 Jscript 모두 IEumVARIANT 를 구현한 컬렉션을 지원한다. 다른 열거자는 지원하지 않는다.
자세한 정보는 아래를 보라.
http://blogs.msdn.com/ericlippert/archive/2003/09/22/53063.aspx
Method names
객체 모델 이름에 A~Z 와 0~9 문자만 사용하라. Unerbar 를 가진 이름은 나쁘다. VB 에서는 라인 결합자(line continuation, _ ) 와 아주 쉽게 혼될 되고, 보기가 흉하다. 피하라.
Jscript 또는 VBScript 예약어 또는 내장(built-in) 객체 모델 엘리먼트와 충돌하는 이름은 역시 나쁜 생각이다.
자세한 정보는 아래를 보라.
http://weblogs.asp.net/ericlippert/archive/2004/06/10/152831.aspx
빠뜨린 점이 분명 있다고 확신한다. 나중에 그 목록에 대해 다시 업데이트할 것을 약속한다.
원문 : http://blogs.msdn.com/ericlippert/archive/2004/07/14/183241.aspx
1. Singleton 패턴
목적
n 어떤 객체가 단 하나만 생성되어 사용되어야 할 때 적용
public class A { private static A instance; private A() {} // 생성자 제한 public static synchronized A getInstance() { if(instance == null) { instance = new A(); return instance; }else return instance; } public static void main(String [] args) { A a1 = A.getInstance(); A a2 = A.getInstance(); if(a1 == a2) { System.out.println("두 객체는 동일합니다."); } } } |
2. Factory Method 패턴
목적
n 객체를 생성하기 위한 인터페이스를 정의
n 서브클래스가 어느 클래스를 인스턴스화 할지를 결정
public abstract class Connection { protected String url; public Connection(String url) { this.url = url; } abstract public void connect(); } class TCPConnection extends Connection { public TCPConnection(String url) { super(url); } public void connect() { System.out.println(url + " 로 TCP 연결을 시도합니다."); } } class UDPConnection extends Connection { public UDPConnection(String url) { super(url); } public void connect() { System.out.println(url + " UDP 연결을 시도합니다."); } } class HTTPConnection extends Connection { public HTTPConnection(String url) { super(url); } public void connect() { System.out.println(url + " HTTP 연결을 시도합니다."); } } |
abstract class ConnectionFactory { abstract public Connection getConnection(String str); } class TCPConnectionFactory extends ConnectionFactory { public Connection getConnection(String url) { return new TCPConnection(url); } } class UDPConnectionFactory extends ConnectionFactory { public Connection getConnection(String url) { return new UDPConnection(url); } } class HTTPConnectionFactory extends ConnectionFactory { public Connection getConnection(String url) { return new HTTPConnection(url); } } |
public class Client { public static void main(String[] args) { ConnectionFactory factory = new TCPConnectionFactory(); Connection socket = factory.getConnection("SOCKET://70.12.113.168:5555"); socket.connect(); ConnectionFactory factory1 = new UDPConnectionFactory(); Connection datagram = factory1.getConnection("DATAGRAM://70.12.113.168:5555"); datagram.connect(); ConnectionFactory factory2 = new HTTPConnectionFactory(); Connection http = factory1.getConnection("HTTP://70.12.113.168:5555"); http.connect(); } } |
3. Abstract Factory 패턴
목적
n 구체 클래스를 명시하지 않고 관련된 혹은 의존적인 객체의 집합을 생성하기 위한 인터페이스를 제공
n 단순하게 객체 하나를 생성하는 경우보다는 여러 개의 객체를 생성해야 하는 경우에 유용
abstract class Head { abstract public void display(); } class CircleHead extends Head { public void display() { System.out.println("둥근 타입의 머리를 가졌습니다."); } } abstract class Leg { abstract public void display(); } class WheelLeg extends Leg { public void display() { System.out.println("바퀴 타입의 다리를 가졌습니다."); } } abstract class Body { abstract public void display(); } class LCDBody extends Body { public void display() { System.out.println("몸통에는 LCD 화면을 가지고 있습니다."); } } abstract class Arm { abstract public void display(); } class FingerArm extends Arm { public void display() { System.out.println("손가락 팔을 가지고 있습니다."); } } |
class Robot { private Head head; private Body body; private Leg leg; private Arm arm; public void addHead(Head head) { this.head = head; } public void addBody(Body body) { this.body = body; } public void addLeg(Leg leg) { this.leg = leg; } public void addArm(Arm arm) { this.arm = arm; } public void displayRobot() { System.out.println("완성된 로봇은 다음과 같은 기능을 가지고 있습니다."); head.display(); body.display(); leg.display(); arm.display(); } } |
abstract class RobotFactory { abstract public Head createHead(); abstract public Body createBody(); abstract public Leg createLeg(); abstract public Arm createArm(); } class HomeRobotFactory extends RobotFactory { public Head createHead() { return new CircleHead(); } public Body createBody() { return new LCDBody(); } public Leg createLeg() { return new WheelLeg(); } public Arm createArm() { return new FingerArm(); } } |
public class Client { public static void main(String[] args) { Robot homeRobot = new Robot(); RobotFactory homeFactory = new HomeRobotFactory(); homeRobot.addHead(homeFactory.createHead()); homeRobot.addBody(homeFactory.createBody()); homeRobot.addLeg(homeFactory.createLeg()); homeRobot.addArm(homeFactory.createArm()); homeRobot.displayRobot(); } } |
4. Builder 패턴
목적
n Product에 대한 다양한 추가 작업으로 인한 결과값의 변형에 유용
n 하나의 Product를 완성하기 위해서 복잡한 작업을 거쳐야 할 경우에도 유용
import java.io.*; abstract class Builder { StringBuffer result = new StringBuffer(); public boolean makeFile(String filename) { try { FileOutputStream fout = new FileOutputStream(filename); DataOutputStream dout = new DataOutputStream(fout); dout.writeUTF(result.toString()); return true; } catch (Exception e) { return false; } } public abstract String getResult(); public abstract void makeTitle(String title); public abstract void makeAuthor(String author); public abstract void makeDate(String date); public abstract void makeSubTitle(String subTitle); public abstract void makeContext(String context[]); } |
class HTMLBuilder extends Builder { public String getResult() { result.append("</body></html>"); return result.toString(); } public void makeTitle(String title) { result.append("<html><<head>"); result.append("<title>" + title + "</title>"); result.append("</head>"); result.append("<body>"); result.append("TITLE : " + title + "<br>"); } public void makeAuthor(String author) { result.append("AUTHOR : " + author + "<br>"); } public void makeDate(String date) { result.append("DATE : " + date + "<br><hr>"); } public void makeSubTitle(String subTitle) { result.append(subTitle + "<br>"); } public void makeContext(String context[]) { result.append("<ul>"); for(int i=0; i<context.length; i++) { result.append("<li>" + context[i] + "</li>"); } result.append("</ul>"); } } |
class Director { private Builder builder; private String filename; public Director(Builder builder, String filename) { this.builder = builder; this.filename = filename; } public String construct() { builder.makeTitle("Member List"); builder.makeAuthor("kkang"); builder.makeDate(" builder.makeSubTitle("A++"); builder.makeContext(new String[]{" builder.makeSubTitle("B++"); builder.makeContext(new String[]{" return builder.getResult(); } public boolean makeFile() { return builder.makeFile(filename); } } |
public class Client { public static void main(String[] args) { Director director = new Director(new HTMLBuilder(), "member.html"); System.out.println(director.construct()); director.makeFile(); } } |
5. Prototype 패턴
목적
n 새로운 객체를 생성할 때 new 연산자를 사용하지 않고 기존의 객체를 복사하여 이용하는 패턴
class Product implements Cloneable { private String name; private int price; public Product(String name, int price) { this.name = name; this.price = price; } public Product cloneMe() throws CloneNotSupportedException { return (Product) clone(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } } |
class Manager { private Product product = null; public Product getProduct() { if(product == null) { product = new Product("design pattern", 10000); return product; } else { try { product = product.cloneMe(); return product; } catch (Exception e) { return null; } } } } |
public class Client { public static void main(String[] args) { Manager manager = new Manager(); Product product = manager.getProduct(); System.out.println("name:" + product.getName()); System.out.println("price:" + product.getPrice()); System.out.println(); Product product1 = manager.getProduct(); System.out.println("name:" + product1.getName()); System.out.println("price:" + product1.getPrice()); System.out.println(); product1.setName("java programming"); product1.setPrice(5000); Product product2 = manager.getProduct(); System.out.println("name:" + product2.getName()); System.out.println("price:" + product2.getPrice()); System.out.println(); } } |
참고
1. 삼성 SDS 멀티캠퍼스 교육 과정 – “자바 개발자를 위한 디자인 패턴” (수강 추천)
2. StarUML 패턴 관련 도움말.객체 지향적인 설계자는
라고 물을 것이다. 프로젝트의 코드 작성 표준에 따라서 "네"라는 답변은 프로그래머가 생성자와 소멸자, 복사 연산자, 할당 연산자를 작성하고 모든 코드에 주석을 작성한 다음, 코드를 구성 제어에 저장해야 한다는 것을 의미한다. 대부분의 프로그래머들은 "아니요,ID를 위해서 완전한 클래스를 생성할 필요는 없습니다. 그냥 int를 사용하겠습니다"라고 결정할 것이다.
방금 무슨 일이 있어났는지 주의 깊게 관찰해 본다.
ID의 게이터 타입을 간단하게 숨길 수 있는 유용한 설계 대안은 고려되지도 않았다.
만약 설계자가
라고 물었다면, 그는 int 대신 IdType으로 대체하는 간단한 타입을 선언하여 ID의 타입을 숨기기로 결정할 것이다. 이 예제에서 객체 지향적인 설계와 정보 은닉의 차이점은 확실하게 규칙에 충돌하는 것보다 미묘하다. 객체 지향적인 설계도 정보 은닉처럼 이러한 설계 결정을 받아들일 것이다.
이 경우에 차이점은, 정보 은닉에 대한 발견적인 사고가 객체 지향적인 사고가 하지 않는 설계 결정들을 장려한다는 것이다.
라고 묻는 것이 인터페이스 설계 문제를 해결하기 위해서 가장 중요하다. 만약 클래스의 비밀을 손상시키지 않고 함수나 데이터를 public 인터페이스에 놓을 수 있다면, 그렇게 하도록 한다. 하지만, 그렇지 않다면 하지 말라.
=> "내가 무엇을 숨겨야 하지?"라고 질문하도록 버릇을 들인다. 그러면 여러분은 얼마나 많은 어려운 설계 문제들이 사라지는지에 놀랄 것이다.
출처 : CODE COMPLETE 2nd Edition -스티브 맥코넬
import java.util.Comparator;
public class Sorters
{
/** 셀 정렬 구현. */
public static void shellSort(Object[] base, Comparator compareStrategy)
{
int i, j;
int gap;
Object p1, p2;
for(gap=1; gap <= base.length; gap = 3*gap + 1)
;
for( gap /= 3; gap > 0 ; gap /= 3)
for( i = gap; i < base.length; i++ )
for( j = i-gap; j >= 0 ; j -= gap )
{
if( compareStrategy.compare( base[j], base[j+gap] ) <= 0)
break;
Object t = base[j];
base[j] = base[j+gap];
base[j+gap] = t;
}
}
// ...
public static void main( String[] args )
{
String array[] = { "b", "d", "e", "a", "e" };
Sorters.shellSort(
array,
new Comparator()
{
public int compare( Object o1, Object o2 )
{
// 역방향으로 정렬
return -( ((String)o1).compareTo((String)o2) );
}
}
);
for ( int i=0; i < array.length; ++i )
System.out.println( array[i] );
}
}