▪Separate Query from Modifier 상태 변경 메서드와 값 반환 메서드를 분리
이 인수 분해 기술은 명령 및 쿼리 책임 분리를 구현
이 원칙은 객체를 변경하는 코드와 데이터를 가져 오는 코드를 분리해야한다는 것을 의미
데이터 가져 오기 코드는 쿼리 이름이다.
쿼리와 수정자를 결합하면 조건을 변경하지 않고 데이터를 가져올 방법이 없다.
즉, 질문을하고 답변을받을 때 답변을 변경할 수 있다.
이 문제는 쿼리를 호출하는 사람이 메소드의 "부작용"에 대해 알지 못해 런타임 오류를 유발할 수있는 경우 더욱 심각 해진다.
그러나 부작용은 객체의 가시 상태를 변경하는 수정 자의 경우에만 위험하다.
예를 들어 객체의 공용 인터페이스, 데이터베이스의 항목, 파일 등에서 액세스 할 수있는 필드 일 수 있다.
수정 자만 복잡한 작업 만 캐시하고 클래스의 비공개 필드에 저장하면 거의 모든 측면 효과.
Problem
값을 반환하지만 객체 내부의 내용을 변경하는 메서드가 있는지?
class Guard { // ... public void checkSecurity(String[] people) { doSendAlert(people); String found = findCriminal(people); someLaterCode(found); } public void doSendAlert(String[] people) { if (findCriminal(people) != "") { sendAlert(); } } public String findCriminal(String[] people) { for (int i = 0; i < people.length; i++) { if (people[i].equals ("Don")) { return "Don"; } if (people[i].equals ("John")) { return "John"; } } return ""; } } |
Solution
메소드를 두 개의 별도 메소드로 분할 예상대로, 그 중 하나는 값을 리턴하고 다른 하나는 오브젝트를 수정해야 한다.
class Guard { // ... public void checkSecurity(String[] people) { String found = findCriminalAndAlert(people); someLaterCode(found); } public String findCriminalAndAlert(String[] people) { for (int i = 0; i < people.length; i++) { if (people[i].equals("Don")) { sendAlert(); return "Don"; } if (people[i].equals("John")) { sendAlert(); return "John"; } } return ""; } } |
대신 임시 변수를 사용한다.
이 리팩토링은 로컬변수를 다루는게 아니라 파라미터를 다루고 있다.
만약 파라미터가 매개변수 참조를 통해 전달되는 경우, 파라미터 값이 이 메소드 안에 변경된 후, 이 값은 메서드 호출 요청 인수로 전달된다.
만약 파라미터 값들이 일반적으로 프로그래밍 언어 값으로 전달(참조가 아닌) 경우에도 이 코딩 특질은 이것에 익숙하지 않는 사람들을 혼란스럽게 한다.
절차
1. 원래 메소드가 수행 한 것을 리턴하는 새로운 메소드를 작성
2. 새 쿼리 메서드를 호출 한 결과 만 반환하도록 원래 메서드를 변경
3. 원래 메서드에 대한 모든 참조를 쿼리 메서드를 호출하지만이 줄 바로 전에 원래 메서드에 대한 호출을 삽입
4. 이제는 적절한 수정 자 메소드가 된 원래의 메소드에서 값을 반환하는 코드를 제거
Benefits
프로그램의 상태를 변경하지 않는 쿼리가있는 경우 메서드를 호출하는 단순한 사실로 인해 의도하지 않은 결과의 변경에 대해 걱정할 필요없이 원하는만큼 여러 번 호출 할 수 있다.
Drawbacks
경우에 따라 명령을 수행 한 후 데이터를 가져 오는 것이 편리하다
예를 들어, 데이터베이스에서 항목을 삭제할 때 삭제 된 행의 수를 알고 싶어 한다.