주가를 곱하는 기능 구현 기능 요구사항 - 다중 화폐를 다루는 보고서를 만들기 위해 화폐 연산 기능을 구현한다. 기능 구현 목록 - 통화가 다른 두 금액을 더해서 환율에 맞게 변환한 금액을 구한다. - 주가를 주식의 수로 곱한 금액을 구한다. 두 번째 기능부터 구현하기 위해 테스트 코드를 작성한다. class MoneyTest { @Test void testMultiplication() { Dollar five = new Dollar(5); five.times(); assertEquals(10, five.amount()); } } 컴파일 오류가 생기는 원인을 정리해보자. Dollar 클래스가 없음 생성자가 없음 times() 메서드가 없음 amount 필드가 없음 public class Dollar { ..
책임과 메시지 객체지향 패러다임이 전통적인 패러다임에 비해 우월한 이유는 뭘까? 객체지향에서는 명확한 책임을 가진 객체들이 협력에 참여해야 한다. 그러나 책임은 ‘어떻게’가 아닌 ‘무엇을’ 이라는 형태로 나타나야 하며, 객체가 책임을 수행하는 방식의 자율성을 보장해주어야 한다. 객체는 메세지를 전송하여 다른 객체에게 접근할 수 있다. 이 메시지에 추가적인 정보가 필요하면 인자(argument)로 이를 표현할 수 있다. 메서드 객체에게 메시지를 전송하면 결과적으로 메시지에 대응되는 메서드가 실행된다. 어떤 메서드를 호출할 지 실행 시간에 결정할 수 있는 것은 객체지향의 핵심이다. 다형성 다형성은 서로 다른 타입에 속하는 객체가 동일한 메시지를 수신할 경우, 서로 다른 메서드로 이를 처리할 수 있는 메커니즘..
타입과 추상화 개념 개념(concept)이란 공통점을 기반으로 객체들을 하나로 묶기 위한 그릇이다. 개념을 이용하면 서로 다른 객체를 여러 그룹으로 분류할 수 있다. 이렇게 분류된 그룹 안에 속한 하나의 객체를 그 개념의 인스턴스 (instance) 라고 한다. 즉, 객체는 특정 개념에 적용되었을 때 ‘인스턴스’라고 부를 수 있다. 따라서 우리가 많은 사물들의 공통점을 통해 개념을 확립하고, 분류하였을 때 비로소 하나의 객체는 인스턴스로 사용될 수 있는 것이다. 개념은 세 가지 관점으로 해석할 수 있다. 심볼 (symbol) - 개념을 지칭하는 명칭 내연 (intension) - 개념의 정의 외연 (extension) - 개념에 속하는 모든 객체의 집합 타입(type) 객체를 분류함으로써 우리는 객체들의..
협력하는 객체들의 공동체 객체지향이라는 예술은 적절한 객체에게 적절한 책임을 할당하는 것에서 시작된다. 객체지향 설계를 하기 전, 객체의 역할을 확립하자. 객체의 역할은 아래와 같은 특징을 가진다. 여러 객체가 동일한 역할을 수행할 수 있다. 하나의 객체가 여러 역할을 수행할 수 있다. 역할은 대체 가능성을 의미한다. 객체는 책임을 다하는 방법을 선택할 수 있다. 협력하는 객체의 덕목 다른 객체의 요청한 것 (what)에 협력적으로 응답한다. 객체가 어떻게 (how) 응답하는 지에 대해 충분히 자율적이다. 객체는 자율적이기 위해서 어떤 행동(behavior)을 하기 위해 필요한 상태(state)를 알고 있어야 한다. 예를 들어, 바리스타는 커피 제조를 위한 방법을 기억하는 상태에 있고, 그렇기 때문에 이..
앞서 트랜잭션 경계를 설정하기 위해 서비스 추상화 기법을 사용하였고, UserService안에 트랜잭션 관련한 코드를 기입하였다. AOP를 사용하는 이유 중 가장 대표적인 것은 선언적 트랜잭션 기능이다. 트랜잭션 경계 설정을 조금 더 세련되게 수정하는 과정에서 AOP를 사용해보는 파트이다. 우선, 이전 시간에서 UserServiceTest에서 UserDao와 MailSender 오브젝트를 호출하여 통합 테스트를 진행하는 것을 실습하였다. 각각의 오브젝트를 직접 고립시켜보고, 외부 DB 등과 같은 환경에 종속되지 않는 단위 테스트를 구현해보자. 트랜잭션 코드의 분리 public void upgradeLevels() throws Exception { // 트랜잭션 시작 TransactionStatus sta..
4장에서 데이터베이스에 접근하는 기술이 다양함을 볼 수 있었듯이, 여러 환경이나 상황에서 기술이 바뀌고 다른 API를 사용하기 때문에 성격이 비슷한 여러 기술을 추상화하고 이를 일관되게 사용할 수 있도록 하는 것은 중요하다. 데이터를 가져오고 입력하는 역할을 하는 UserDao에 사용자의 레벨을 관리하는 기능을 추가하고 싶다. 그러나 레벨 관리와 관련한 복잡한 비즈니스 로직은 UserDao가 아닌 비즈니스 로직 서비스를 제공한다는 의미에서 UserService에서 관리한다. UserService는 UserDao의 빈을 DI 받아 사용한다. UserDao의 구현 클래스가 바뀌어도 UserService는 영향을 받지 않는다 public class UserService { UserDao userDao; pub..
모든 예외는 적절하게 복구되거나 작업을 중단시키고 개발자에게 통보되어야 한다. 자바에서 프로그램 상에 Throw 할 수 있는 예외는 총 세가지 종류가 있다. 예외의 종류 java.lang.Error의 서브 클래스 OutOfMemoryError나 ThreadDeath와 같이 자바 VM에서 발생시키는 에러를 말한다. Exception과 Checked Exception 개발자의 애플리케이션 코드에서 발생한 에러이다. Checked Exception이란 Exception의 서브 클래스이면서 RuntimeException을 상속하지 않은 것을 의미한다. 체크 예외가 발생하는 코드를 작성할 때는 예외를 처리하는 코드를 반드시 함께 작성한다. 예를 들어, 존재하지 않는 파일의 이름을 입력한 FileNotFoundEx..
이전 포스팅에서 알아본 UserDao와 JdbcContext, StatementStrategy의 구조는 템플릿/콜백 패턴과 관련이 있다. 템플릿/콜백 패턴 바뀌지 않는 일정한 패턴을 갖는 작업 흐름 ( = 템플릿) 이 존재하고 그 중 일부분을 변경해야하는 전략 패턴 구조에 익명 내부 클래스 ( =콜백)을 활용한 방식을 의미한다. 두 가지 용어에 대해서 조금 더 알아보자. 템플릿 (template) : 어떤 목적을 위해 만들어 둔 고정된 로직(틀)이다. 템플릿 메소드 패턴은 바뀌지 않는 템플릿 메소드를 상위 클래스에 두고, 바뀌는 부분을 서브 클래스의 메소드로 오버라이딩하는 구조를 가지고 있다. 콜백 (callback) : 실행되는 것을 목적으로 다른 오브젝트에 전달되는 오브젝트를 의미한다. 메소드가 담긴..
이전 포스팅에서, UserDao의 코드에서 예외처리 구문을 추가하고, 디자인 패턴을 이용해 각 테스트 코드에서 쿼리문을 실행하는 PrepareStatement 객체를 생성하는 작업을 최적화하였다. 변하는 부분을 메소드로 추출한 메소드 추출 기법, 추상 메서드를 오버라이딩하는 템플릿 메소드 패턴, 그리고 인터페이스를 생성하여 각각의 PrepareStatement 생성 방법마다 구현 클래스를 만드는 전략 패턴을 고려하였다. 전략 패턴에서 테스트 메소드 안에 직접적으로 구현 클래스가 결정되는 현상을 막기 위해서 컨텍스트 코드를 분리하고, 테스트 메소드는 하나의 클라이언트로 작동하도록 하였다. 즉 DI를 사용해 클라이언트 (UserDao) 와 컨텍스트 (jdbcContextWithStatementStrategy..