Head First Design Pattern 요약 #1 – Strategy, Observer

Chapter 1. 디자인 패턴 소개

최초설계
Duck[꽥(), 수영(), 표시()] <— 오리1 [표시()] <— 오리2 [표시()]

날기 추가 : 오리1, 오리2도 날수 있게 됨
Duck[꽥(), 수영(), 표시(), 날기()] <— 오리1 [표시()] <— 오리2 [표시()]

고무로된 오리도 날수 있게됨 : 문제발생
Duck[꽥(), 수영(), 표시(), 날기()] <— 오리1 [표시()] <— 오리2 [표시()] <— 고무오리 [꽥(//삑삑으로 오버라이드), 표시()]

고무로된 오리도 날수 있게됨 :  고무오리의 날기()를 오버라이드로 처리하여 못날게 함
Duck[꽥(), 수영(), 표시(), 날기()] <— 오리1 [표시()] <— 오리2 [표시()] <— 고무오리 [꽥(//삑삑으로 오버라이드), 표시(), 날기(//아무것도 안함)]

나무오리 : 꽥을 아무것도 안함으로 오버라이드
Duck[꽥(), 수영(), 표시(), 날기()] <— 오리1 [표시()] <— 오리2 [표시()] <— 고무오리 [꽥(//삑삑으로 오버라이드), 표시(), 날기(//아무것도 안함)] <— 나무오리 [꽥(//아무것도 안함), 표시(), 날기(//아무것도 안함)]

매번 오버라이드로 뻘짓하기 싫어져서 인터페이스를 사용하기로 함
날수있음[날기()]                                               <— 오리1 [표시(), 날기(), 꽥()] 꽥꽥거릴수 있음[꽥()]                                        <— 오리2 [표시(), 날기(), 꽥()] 오리[수영(), 표시(), 기타오리관련메소드()]           <— 고무오리 [표시(), 꽥()] <— 나무오리 [표시()]

변화 : 날기()를 고쳐라 요구사항 들어옴 -> ‘날수있음’을 상속받은 모든 오리를 고쳐야 -> 오류발생 높아질 수도

 

디자인 원칙 #1

Application에서
달라지는 부분과
달라지지 않는 부분을(요놈을 뽑아서(리팩토링) 캡슐화하면 요 부분만 고치거나 확장가능하다.)
분리해라

바뀌는 부분과 안 바뀌는 부분 분리
바뀌는 부분 : 날기(), 꽥() –> {꽥(), 삑(), 뽕()} 처럼 관련된 클래스 집합을 만듬
안 바뀌는 부분 : 표시()

 

디자인 원칙 #2

구현이 아닌 인터페이스에 맞춰 프로그래밍 한다.

 

위의 각 클래스 집합을 인터페이스로 만들어봄
날기행동_인터페이스[날기()]    <— 날개로날기[날기()] <— 못날기[날기(//아무것도 안함)]

다형성을 위해 추상수퍼클래스로도 사용 가능
동물_추상[소리냄()]    <— 강아지[소리냄(){멍()}  멍(){짖음}] <— 고양이[소리냄(){뮤()}  뮤(){울음}]

개 만들기 #1                           개 만들기 #2                                     개 만들기 #3
Dog d = new Dog();                Animal animal = new Dog();            a = getAnimal();
d.멍();                                   animal.소리냄();                               a.소리냄();

실제 구현
….

“A는 B이다” 보다 “A에는 B가 있다”
구성을 사용함으로써 유연성을 크게 향상 시킬 수 있음

 

디자인 원칙 #3

상속보다는 구성(composition)을 사용하라

 

드디어 첫번째 패턴이!!!

 

스트래티지 패턴(strategy pattern)
알고리즘군을 정의하고 각각을 캡슐화하여 교환해서 사용할 수 있도록 만듬
스트래티지를 활용하면 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다.

 

디자인 패턴 필요성

  1. 개발자간 서로 사용하는 패턴 용어
  2. 패턴을 이용하면 간단한 단어로 많은 것을 얘기할 수 있음 : 이번건은 스트래티지 패턴으로 할꺼야
  3. 디자인에 더 집중할 수 있음 : 구현 생각하느라 논점이 빗나가지 않음
  4. 전문용어 사용으로 개발팀의 능력 향상 : 오해의 소지가 줄고 빠른 작업 가능
  5. 신참개발자에게 자극

 

참고자료 : 다형성(polymorphism)

더보기

살짝 길어 질수도 있는 문제인데요.
최대한 간단히 대답하도록 노력하겠습니다.

먼저 다형성이라는게 먼지 알아 보겠습니다.
다형성이란 주어진 타입의 변수 하나가 여러 타입의 객체를 참조하는데 사용되고,
변수가 참조하는 객체의 타입에 맞는 메소드를 자동으로 호출할 수 있는 능력.
즉 다형성이란 특징을 사용하면 특정한 메소드 하나를 호출하면 호출이 적용되는 객체의 타입에 따라서
서로 다르게 작동하도록 만들수 있다는 이야기가 됩니다.

예를들어서 동물들을 예로 들어 보겠습니다.

class Dog{
void bark(){
System.out.println(“개소리”);
}
}

class Cat{
void bark(){
System.out.println(“고양이”);
}
}

class Lion{
void bark(){
System.out.println(“사자소리”);
}
}

이러한 클래스를 가지고 각각을 호출하기 위한 메소드를 만들겠습니다.

class Animal{
public static void main(String args[]){
Dog d = new Dog();
Cat c = new Cat();
Lion l = new Lion();

d.bark();
c.bark();
l.bark();
}
}

이렇게 작성이되면 각각의 동물소리를 부를수가 있습니다.
여기에 한가지를 추가 하겠습니다.
바로 동물들을 치료하는 수의사를 추가해볼께요.
수의사는 동물에게 주사를 놓을때 동물 소리가 난다고 가정을 할게요.

 

class Doctor{
void Dog_shot(){
System.out.println(“개소리”);
}
void Cat_shot(){
System.out.println(“고양이소리”);
}
void Lion_shot(){
System.out.println(“사자소리”);
}
}

이렇게 작성하면 되겠죠..

그리고 테스트 하는곳에 추가를 해보겠습니다.

class Animal{
public static void main(String args[]){
Dog d = new Dog();
Cat c = new Cat();
Lion l = new Lion();

 

Doctor doc = new Doctor();
       doc.Dog_shot();
doc.Cat_shot();
doc.Lion_shot();

//이렇게 각각의 동물들에게 주사를 하려면 이부분을 추가를 해야 합니다.

d.bark();
c.bark();
l.bark();
}
}

 

하지만 여기서 문제점을 살펴 봅시다.
동물들이 추가가 된다면 어떻게 되죠?
당연히 Doctor클래스에 메소드를 추가해야 한다는 애기가 됩니다.
동물이 수십마리가 추가되면 추가되는 메소드 또한 수십개가 되며, 프로그래머로써는
엄청난 삽질(?)이 될수 도 있습니다.
이를 편리하게 하기 위해 다형성을 사용하겠습니다.
이를 위한 상위 클래스를 하나 만들게요. 클래스로 해도 되고 인터페이스로도 해도 되지요.
전 간단히 클래스로 작성하겠습니다.
abstract class Ani{
void bark();
}

 

이렇게 만들어 두시구요 각각의 동물클래스는 이제 위에 만들 클래스를 상속받게 합니다.

class Dog extends Ani{
void bark(){
System.out.println(“개소리”);
}
}

class Cat extends Ani{
void bark(){
System.out.println(“고양이”);
}
}

class Lion extends Ani{
void bark(){
System.out.println(“사자소리”);
}
}

 

이렇게 하시면.. 코드양만 많아 지는건 아니냐 하시겠지만 다음 Doctor클래스를 만들때 엄청난
노가다에서 벗어 나실수 있습니다.

class Doctor{
void shot(Ani a){
a.bark();
}
}

이렇게 해놓으시면 이제 main함수를 다시 수정하겠습니다.

class Animal{
public static void main(String args[]){
Ani d = new Dog();
Ani c = new Cat();
Ani l = new Lion();

 

Doctor doc = new Doctor();
       doc.shot(d);
doc.shot(c);
doc.shot(l);
       // 이러한 식으로 수정을 하시면됩니다.
// 도대체 이게 머가 좋은거냐….
// 이제 동물을 수십마리 추가를 하셔도 위에서 만든 상위클래스 Ani클래스만 상속 받으시면
// Doctor클래스에는 메소드 추가없이(노가다없이?) 사용이 가능하다는 이말입니다.

d.bark();
c.bark();
l.bark();
}
}

도움이 되셧는지 모르겠네요.
출처 : 지식인

 

참고자료 : 일반클래스, 추상클래스, 인터페이스

더보기

일반클래스
public class TestAbstract {
public void func1() {
System.out.println(“일반 method”);
}
public void func2() {
System.out.println(“일반 method”);
}
}
보통 클래스는 위처럼, method의  선언부와 구현부분으로 구성되어지죠
메소드의 선언부는 public void func1(), public void func2()  가되구요.
구현부분의 fun1(), fun2()메소드안의 내용이 됩니다.

추상클래스 (abstract)
public abstract class TestAbstract {
public abstract void func1() ;
public void func2() {
System.out.println(“일반 method”);
}
}
위의 예제에서 func1()은 좀 이상하게 생겼죠?  다시 말해 method의 prototype (선언부)만 있지 실제 method body는 없다(이런 method를 가리켜 abstract method라고 한다). 또한 이 같은 method를 만들 때 abstract란 키워드가 사용되구요.
이 같은 abstract method를 하나라도 가지고 있는 class는 abstract class로 정의해야 합니다. 이런 클래스가 추상클래스죠.

인터페이스 (Interface)
public interface Test {
public static final int XXX = 7;
public int YYY = 8;

public void func1();
        public void func2();
}
바로 전에 abstract class에 대해서 설명했죠? 이것은 abstract method를 가지고 있는 class이다. 그런데 abstract class는 abstract method가 아닌, 즉 body를 가지고 있는 일반 method도 가질 수 있다.
그런데, interface라는 것은 일종의 abstract class인데, 이것이 가지고 있는 method들은 모두가 반드시 abstract method들이어야 한다. 다시 말해서 abstract method만 가지고 있는 abstract class가 interface인 것입니다.

그리고, 추상클래스나 인터페이스는
Test tObject = new Test() 와 같은 형식으로 객체를 생성할수 없죠.
일반클래스는 가능하지만..
추상클래스나 인터페이스는 그클래스를 직접적으로 사용하는것이아니라,

class Child implements Test {
public void func1() {
System.out.println(XXX);
}
public void func2() {
System.out.println(YYY);
}
}

처럼, 인터페이스나, 추상클래스를 상속받은 클래스를 사용하게 되죠.

Test   tObject = new Child();
Child  cObject = new Child();

위 두개모두가 가능합니다.

 

출처 : 지식인

 

 

추상클래스

인터페이스

클래스이다.

추상클래스의 일종이다.

하나 이상의 추상메소드를 가진다.

public abstract class TAbstract {

public abstract void func1() ;

public void func2() {

System.out.println(“func2”);

} }

모든 메소드가 추상메소드이다.

public interface TInterface {

public static int num = 8;

public void func1();

public void func2();

}

상속 받을 때 extends를 사용

상속받을 때 implements 사용

단일 상속만 가능

다중 상속 가능

추상클래스를 상속받은 클래스에서 상속해준 클래스의 추상메소드를 모두 구현해야 한다.

인터페이스를 구현한 클래스에서는 반드시 인터페이스내의 메소드를 구현한다.

 

출처 : 디벨로퍼 짱

 

쉬어가기

내가 진정 중요하게 생각하는 것들 : 김창준 (애자일 컨설팅 대표)
http://www.ibm.com/developerworks/kr/library/dwclm/20080226/
테러리스트에서 버그까지 : 김창준 (애자일 컨설팅 대표)
http://www.ibm.com/developerworks/kr/library/dwclm/20080422/

사용자 삽입 이미지

 

 

Chapter 2. 옵져버 패턴

기상 모니터링 Application 개발 의뢰 (개발 범위는 핑크)
온도/습도/압력센서 — 기상스테이션 <— WetherData객체 —>디스플레이 장비(현재상태, 통계, 예보)
                                                                                         확장가능하도록 API 도 만들것

WetherData 클래스
WetherData[getTemperature(), getHumidity(), getPressure(), mesurementsChange()] ↖ 온도getter         ↖습도getter    ↖기압getter    ↖기상관측값이 갱신될때마다 알려주는 메소드

첫번째 대충 만든 코드

 

위 코드의 문제점은?
– parameter 가 맨날 똑같다.. 공통 부분
– 9~11줄은 바뀔 수 있는 부분 -> 캡슐화 하자 (스트래티지 패턴)
– 9~11줄은 구체적인 구현이므로 다른 디스플레이를 위해서는 코드를 고치는 수밖에 없다.

옵져버 패턴이란?
– 옵져버 패턴 = 출판사(subject) + 구독자(observer)
– 구독 / 해지 가능
– subject 객체는 데이타가 달라지면 observer 객체에게 값을 전달

 

Observer Pattern

한 객체의 상태가 바뀌면
그 객체에 의존하는 다른 객체들에게 연락이 가고 자동으로 내용이 갱신되는
ont-to-many 의존성을 정의함

옵저버 패턴 : 클래스 다이어그램

<<인터페이스>>
Subject

registerObserver()
removeObserver()
notifyObserver()

↑ 인터페이스 상속

 ——>
옵저버

<<인터페이스>>
Observer

update()

↑ 인터페이스 상속

ConcreteSubject

registerObserver() {내용}
removeObserver() {내용}
notifyObserver() {내용}getState()
setState()
<—-
주제

ConcreteObserver

update() {내용}


느슨한 결합(Loose Coupling) : subject와 observer가 느슨하게 묶임 (서로가 서로를 모름)

  • subject가 observer에 대해 아는건 observer가 특정 인터페이스를 구현한다는 것 뿐 : update()
  • observer는 언제든 새로 추가 가능
  • 새 observer를 추가해도 subject를 변경할 필요 없음
  • subject 와 observer는 독립적으로 재사용 가능
  • subject 또는 observer가 변경되어도 서로 영향 안 미침

 

디자인 원칙 #4
서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용하라
–> 변경사항이 생겨도, 객체사이의 상호 의존성을 최소화하여 변경가능한 유연성 확보 가능

 

기상 스테이션 설계
사용자 삽입 이미지

 

JAVA 에서는..
java.util.Observer 인터페이스, java.util.Observeable 클래스 가 있음
스윙에서도 옵저버 패턴을 사용함 (e.g. JButton 의 ActionListener)

 

참고자료

닷넷환경 UML : http://www.zdnet.co.kr/builder/dev/modeling/0,39031637,39134439,00.htm
StarUML : http://cafe.naver.com/staruml
샤프심 흑심 품다 : http://blog.empas.com/mcm27xx/read.html?a=4093369
UML 이해하기 :

Download

사용자 삽입 이미지

CC BY-NC-ND 2.0 KR

이 저작물은 크리에이티브 커먼즈 저작자표시-비영리-변경금지 2.0 대한민국 라이선스에 따라 이용할 수 있습니다. 크리에이티브 커먼즈 라이선스

저작권과 관련된 파일요청 및 작업요청을 받지 않습니다.

댓글 남기기