Refactoring - Chapter 8.2

540 views

Published on

Refactoring[Martin Fowler] Chapter 8

Published in: Software
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
540
On SlideShare
0
From Embeds
0
Number of Embeds
39
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Refactoring - Chapter 8.2

  1. 1. Chapter 8-2 데이터 체계화 - JuL-
  2. 2. 마법 숫자를 기호 상수로 전환 (Replace Magic Number with Symbolic Constant) • 마법 숫자는 특수한 값을 갖는 숫자를 일컫는 용어로 , 여러 곳에서 논리적으로 같은 숫자를 참조해야 할 경우가 많은데 , 수정해야 할 상황이 오면 끔찍한 일이 발생한다 . • 즉 , 상수를 하드코딩하지 말자 . class TestA{ public boolean isOverFlow(int curCount){ if(curCount > 10){ return true; } return false; } } class TestB{ public int getMaxCount(){ return 10; } } class TestA{ public boolean isOverFlow(int curCount){ if(curCount > CommonConst.MAX_COUNT){ return true; } return false; } } class TestB{ public int getMaxCount(){ return CommonConst.MAX_COUNT; } } interface CommonConst{ public int MAX_COUNT = 10; }
  3. 3. 필드 캡슐화 (Encapsulate Field) • 데이터는 절대로 public 으로 선언하면 안된다 . 반드시 private 형태에서 setter, getter 를만들어 사용해야 한다 . • 얼핏 생각하기엔 , publi 으로 하든 , setter, getter 를 만들든 외부에서 값을 변경할 수 있는 것은 매한가지 아닌가 라고 생각할 수 있지만 , 실제 코딩을 해보면 그렇지 않다 는 것을 느낄 수 있다 . 예를 들어 , 아래와 같은 사소한 실수를 미연에 방지할 수도 있 고 , 무엇보다 변수를 호출하거나 세팅할 때 일괄 처리해야 할 코드가 추가될 경우 해 당 변수의 setter, getter 를 수정하는 것만으로 대응할 수 있다 . class MyObject{ public int mId = -1; } MyObject myObj = new MyObject(); myObj.mId = 2; // 빌드에러 없이 컴파일 된 후 엄청난 side effect 를 마주하게 됨 . class MyObject{ private int mId = -1; public int getId(){ return mId; } public void setId(int id){ mId = id; } } MyObject myObj = new MyObject(); myObj.mId = 2; // 빌드 에러 발생
  4. 4. 컬렉션 캡슐화 (Encapsulate Collection) • 컬렉션 ( 배열 , 리스트 , 세트 , 벡터 ) 의 getter 는 객체 자체를 반환해서는 안된다 . • Java 는 기본적으로 pass by value 지만 , object 를 pass 할 때는 object 의 reference 가 value 로써 passing 된 다는 것을 기억하자 . • Thread safe 한 컬렉션 객체를 만들기에도 더 용이하다 . public void foo(Dog d) { d.getName().equals("Max"); // true d = new Dog("Fifi"); d.getName().equals("Fifi"); // true } Dog aDog = new Dog("Max"); foo(aDog); aDog.getName().equals("Max"); // true public void foo(Dog d) { d.getName().equals("Max"); // true d.setName("Fifi"); } Dog aDog = new Dog("Max"); foo(aDog); aDog.getName().equals("Fifi"); // true
  5. 5. 레코드를 데이터 클래스로 전환 (Replace Record with Data Class) • 프로그래밍 환경에서 흔히 사용되는 레코드 구조를 덤 데이터 개체로 전환한다 . • 덤 데이터란 , 데이터가 거의 들어 있지 않은 객체로 , 기능 추가 없이 데이터에 public 속성이나 읽기 / 쓰기 메서드로 접근할 수 있다 . 프로 그래머 입장에선 객체지향 프로그래밍 개념의 정통적 개념에 위배된 다 . 패턴 / 안티패턴의 사용은 캡슐화에 완전히 위배된다 .
  6. 6. 분류 부호를 클래스로 전환 (ReplaceType Code with Class) • 숫자형 분류번호를 별도의 클래스로 전환하면 코드가 상당히 이해하기 쉬워진다 . • 책이 집필된 시점의 java version 엔 enum type 이 없어서인지 enum type 같은 class 를 별도로 만들어서 설명하고 있다 . 참고만하고 그냥 enum type 을 쓰면 될듯 ? public enum Blood { O(1), A(2), B(3), AB(4); private int value = 0; Blood(int i) { value = i; } public int getNumber() { return value; } public static Blood get(int value) { if (value == O.getNumber()) return O; else if (value == A.getNumber()) return A; else if (value == B.getNumber()) return B; else if (value == AB.getNumber()) return AB; return AB; } }
  7. 7. 분류 부호를 하위클래스로 전환 (ReplaceType Code with SubClasses) • 분류 부호가 클래스 기능에 영향을 줘서 클래스로 전환 기법을 사용할 수 없을 경우 재정의를 통해 조금씩 다른 기능을 처리하게 한다 . • 이와 같이 이 기법은 다형성을 가능케하는 사전작업으로 시행할 때가 많다 . public class Employee { private int _type; static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; Employee (int type) { _type = type; } } public class Engineer extends Employee { protected Engineer(int type) { super(type); } @Override public int get_type() { return Engineer.ENGINEER; } } public abstract class Employee { private int _type; static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; protected Employee(int type) { _type = type; } public static Employee createEmployee(int type) { // if(type == ENGINEER) return new Engineer(type); // else return new Employee(type); switch (type) { case ENGINEER: return new Engineer(type); case SALESMAN: return new Manager(type); case MANAGER: return new Manager(type); default: throw new IllegalArgumentException(“Incorrect Type Code”); } } abstract int get_type(); }
  8. 8. 분류 부호를 상태 / 전략 패턴으로 전환 (ReplaceType Code with State/Strategy) • 이 기법은 “분류 부호를 하위클래스로 전환"과 비슷하지만 , 분류 부호 가 객체 수명주기 동안 변할 때나 다른 이유로 하위클래스로 만들 수 없 을 때 사용한다 . class Employee { private int _type; static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; Employee (int type) { _type = type; } int payAmount() { switch (_type) { case ENGINEER: return _monthlySalary; case SALESMAN: return _monthlySalary + _commission; case MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } }
  9. 9. 분류 부호를 상태 / 전략 패턴으로 전환 (ReplaceType Code with State/Strategy) class Engineer extends EmployeeType { int getTypeCode () { return Employee.ENGINEER; } } class Manager extends EmployeeType { int getTypeCode () { return Employee.MANAGER; } } class Salesman extends EmployeeType { int getTypeCode () { return Employee.SALESMAN; } } class EmployeeType... static EmployeeType newType(int code) { switch (code) { case ENGINEER: return new Engineer(); case SALESMAN: return new Salesman(); case MANAGER: return new Manager(); default: throw .. } } static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; } class Employee... int getType() { return _type.getTypeCode(); } void setType(int arg) { _type = EmployeeType.newType(arg); } int payAmount() { switch (getType()) { case EmployeeType.ENGINEER: return _monthlySalary; case EmployeeType.SALESMAN: return _monthlySalary + _commission; case EmployeeType.MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } }
  10. 10. 하위클래스를 필드로 전환 (Replace Subclass with Fields) • 단순히 상수 메서드만 존재하는 하위클래스는 상위클래스의 필드로 전 환하고 , 하위클래스는 완전히 삭제하면 된다 . abstract class Person { abstract boolean isMale(); abstract char getCode(); ... } class Male extends Person { boolean isMale() { return true; } char getCode() { return 'M'; } } class Female extends Person { boolean isMale() { return false; } char getCode() { return 'F'; } } abstract class Person { private final boolean _isMale; private final char _code; static Person createMale(){ return new Person(true, 'M'); } static Person createFemale(){ return new Person(false, ‘F'); } ... }

×