냄새 나는 Switch 코드와 다형성

원문 : Switch Statement code smell and polymorphism
위 글을 보면서 정리하고 있습니다.

switch-case 문을 사용한 소스코드를 보겠습니다.
[#M_ more.. | less.. |
public class Client {
  private double a;
  private double b;
  private double r;
  …
  public double calculateArea(int shape) {
      double area = 0;
      switch(shape) {
          case SQUARE:
              area = a * a;
              break;
          case RECTANGLE:
              area = a * b;
              break;
          case CIRCLE:
              area = Math.PI * r * r;
              break;
      }
      return area;
  }

  public double calculatePerimeter(int shape) {
      double perimeter = 0;
      switch(shape) {
          case SQUARE:
              perimeter = 4 * a;
              break;
          case RECTANGLE:
              perimeter = 2 * (a + b);
              break;
          case CIRCLE:
              perimeter = 2 * Math.PI * r;
              break;
      }
      return perimeter;
  }
  …
}
_M#]
위 코드를 보시면 swtich-case 문이 두 개의 메소드에서 중복이 되며 이것은 리팩토링이 필요하다는 것을 뜻합니다.

이 코드는 instanceOf 연산자를 사용해서 간추릴 수는 있지만 여전히 중복이 존재합니다. 이럴 때 다형성을 사용하려면 먼저 AbstractShape 클래스나 Shape라는 인터페이스를 만듭니다. 그리고 이를 구현 하거나 상속 받도록 구성합니다.

출처 : http://photos1.blogger.com/blogger/2606/2479/1600/ClassDiagram1.gif

위 UML 대로 코딩한 소스 코드는 다음과 같습니다.
[#M_ more.. | less.. |
Shape.java file
public interface Shape {
 
public double getArea();
  public double getPerimeter();
}

Square.java file
public class Square implements Shape {
  private double a;
  …
  public double getArea() {
      return a * a;
  }
  public double getPerimeter() {
      return 4 * a;
  }
}

Rectangle.java file
public class Rectangle implements Shape {
  private double a;
  private double b;
  …
  public double getArea() {
      return a * b;
  }
  public double getPerimeter() {
      return 2 * (a + b);
  }
}

Circle.java file
public class Circle implements Shape {
  private double r;
  …
  public double getArea() {
      return Math.PI * r * r;
  }
  public double getPerimeter() {
      return 2 * Math.PI * r;
  }
}
_M#]
이제 Client 코드에서는 switch 문이 사라집니다.

public class Client {
  private
Shape shape;
  …
  public double calculateArea() {
      return
shape.getArea();
  }
  public double calculatePerimeter() {
      return
shape.getPerimeter();
  }
}


Clinet의 코드가 처음 것에 비해 굉장히 단순해 졌으며 유연해 졌습니다. 새로운 도형이 추가 되어도 그 도형이 Shape 인터페이스만 구현했다면 이 코드는 수정될 필요가 없어졌습니다.

책임이라는 관점에서 살펴본다면 처음의 Client 코드는 도형의 세부 길이 까지 너무 많은 걸 알고 었는데 반해 여기서는 도형이 뭘 할 줄 아느냐만 (메소드만) 을 이용하고 있습니다.

인터페이스와, 다형성을 사용한 swich문의 중복과 coupling을 해결한 재밌는 글이였습니다.

배고픔의 자서전

‘아멜리 노통브’라는 작가의 자서전을 읽었습니다. 처음 책을 받아 들었을 때는 ‘어라 얇네 읽는데 얼마 안걸리겠군.’ 이라는 생각을 했습니다. 책은 하루에 1시간 30분 정도 봅니다. 통학 시간에 버스에서 책을 보지요.

하지만 시작 하자마자 고도의 언어 유희와 고상한 표현으로 인해서 머리가 지끈 거리기 시작하더니 어느새 그러한 표현에 제 머리가 익숙해져 가는 것을 느꼈습니다.

그리고 글로 표현되어 있는 작가의 경험을 통한 감정이 그대로 전달되는 것을 느꼈습니다. 정말 색다른 경험이였습니다. 이 책과 혼열일체가 되어 작가가 일본의 유치원에 있을 때 이야기를 할 땐 인상을 쓰면서 보고 뉴욕에서 친구들이 서로 자신의 손을 잡겠다며 싸우는 모습을 보며 웃을 땐 저도 버스에서 웃고 있었습니다. 그리고 벨기에에서 심하게 병들었을 땐 저 역시 울상이 되었지요.

어떻게 독자를 자신의 이야기에 푹 빠져들게 하는가? 는 관심이 없지만 어떻게 제가 이렇게 이 책에 빠져들었을까? 하는 것은 저에게 중요하고 궁금합니다.

아무래도 솔직함을 보았기 때문인 것 같다는 생각이 큽니다. 이 작가는 너무도 솔직합니다. 독자에게 호감을 사려고 글을 쓰지 않았습니다. 철저히 자신의 이야기를 자신의 스타일로 써나가고 있습니다. 제가 본받고 싶은 모습입니다. 책의 표지에 ‘독창성과 실랄한 문체’라고 표현해 주고 있는데 전 쉽고 단순하게 솔직한 표현이라고 말하고 싶네요.

부디 건강하게 오래 오래 많은 이야기를 들려 주었으면 좋겠습니다.

Map 인터페이스 살펴보기

콜렉션에 관한 java 튜토리얼을 보면서 정리해 봅니다.

Map은 키와 값의 쌍으로 이루어진 map을 나타내는 객체입니다. 키는 DB의 주키 처럼 중복이 발생하면 안됩니다. 그리고 하나의 키는 최대한 하나의 값과 매칭 됩니다.

Map에서 제공하는 책임들로는 다음과 같은 메소드들이 있습니다.

1197165374.bmp본문에 있던 내용입니다.
[#M_ more.. | less.. |

public interface Map<K,V> {

// Basic operations
V put(K key, V value);
V get(Object key);
V remove(Object key);
boolean containsKey(Object key);
boolean containsValue(Object value);
int size();
boolean isEmpty();

// Bulk operations
void putAll(Map<? extends K, ? extends V> m);
void clear();

// Collection Views
public Set<K> keySet();
public Collection<V> values();
public Set<Map.Entry<K,V>> entrySet();

// Interface for entrySet elements
public interface Entry {
K getKey();
V getValue();
V setValue(V value);
}
}

_M#]

잔인함

“연탄재 함부로 발로 차지 말아라. 너는 언제 연탄처럼 남을 위해서 뜨거웠던 적이 있느냐” 안도현님의 ‘너에게 묻는다’라는 시입니다.

등교길에 똥개를 봤습니다. 귀엽더군요. 발발 거리며 거닐다가 어떤 여자의 근처에 가서 멈추더니 그 여자를 쳐다봅니다. 여자는 ‘이쁜건 알아가지고’ 하는 표정으로 지나갑니다. 저는 ‘별로 이쁘지도 않은데 눈이 낮구나…’ 하면서 사람에게 친근하게 구는 강아지 모습에 기분이 흐믓해졌습니다.

그런데 갑자기 제 뒤에서 어떤 아저씨가 그 강아지를 발로 찰 기세로 달려오더니 강아지가 놀래서 도망가게 하고 가던길을 계속 갑니다. 저는 순간 그 사람이 강아지를 발로 차는 줄 알고 머릿속에 강아지가 깨갱 거리는 환상을 보았습니다.

대체 왜 저러는 건가… 왜 이유 없이 강아지에게 겁을 주고 나에겐 기분 나쁜 상상을 심어준 건가..대체 이유가 뭐냐 이 잔인한 아저씨야!! 강아지야 잘 기억해 뒀다가 다음부턴 콱 물어버려라. 파이팅!!

수정해야 할 것들

1. 테스트 클래스와 기능 클래스와 1:1 매칭이 안됨.(완료)
=> Abstract 클래스 사용해서 1:1 매칭 시킴.

2. 메소드 작명의 문제점(완료)
=> getById, getByName은 이상함. get(식별자) 이런 형태가 보통임. 메소드 이름 수정하기. getByName은 FindByName과 같이 검색용도로 바꾸자.
=> Alt + Shift + r 이 유용하게 사용됨.

3. get을 했을 때 한글이 ??? 이렇게 보이는 문제점.(완료)
=> DB에 인코딩을 UTF-8로 세팅을 해줘야 함.
=> 한수형 블러그 참조. 한수형 베리 베리 쌩큐요. 🙂

4. Member 테이블의 id 속성이 Auto_incremental 일 때 id를 예측할 수가 없는 문제점.(완료)
=> iBatis의 selectKey라는 것을 사용해서 해결 해야함. DB마다 사용되는 위치가 다르다고 함.

5. 현재 작성한 test는 서비스 테스트가 아니라 Dao 테스트.(구현 중)
=> 서비스 테스트는 Member Table에 접근하는게 아니라 그냥 Member Service 메소드들만 테스트 하는 거기 때문에 MemberDao를 대신할 Mock이 있어야 할 듯.(Mock을 어떻게 사용하는지 모름. 영회형이 다음 스터디때 발표 하실 듯. 물론 그전에 영회형 블러그를 보며 공부하는게 좋겠다.)

6. Dao 테스트 할 때 jdbcTamplate 객체를 쓰든 iBATIS를 쓰는 둘 중 하나를 사용해야 하는데 둘 다 사용함.(완료)
=> 버스타고 가야 하는데 택시타고 가는꼴… iBATIS를 사용하도록 수정 하자.

7. Log 메시지를 안 뿌린다.(완료)
=> Log 메시지를 봐야 어디가 잘못됐는지 알 수 있다.
=> 하지만 로그를 어떻게 찍지? Spring in action에서 얼핏 본적이 있는데.. 뒤져봐야겠다.

8. 아직 구현되지 않은 기능들이 있음.(구현 중)
=> find와 paging을 하기 위한 기능들 구현 해야함.

소스코드 체크아웃 받는 곳(SVN) : http://agilejava.googlecode.com/svn
지난 스터디 발표 자료 : 보기

해야할 것들(구현 중이거나 아직 손도 안댓 것들)

5. 현재 작성한 test는 서비스 테스트가 아니라 Dao 테스트.(구현 중 50%)
8. 아직 구현되지 않은 기능들이 있음.(구현 중 50%)

언능하자! 파이팅!