조립기(Assembler)
DI를 활용하면 객체 생성에 사용할 클래스를 변경하기 위해 객체를 주입하는 곳만 변경하면 되는 것이라고 우리는 알고 있습니다. 하지만 DI를 활용해서 클래스를 작성했더라도 그 객체를 main메서드에서 주입하는 것보다 의존 객체를 주입하기 위한 클래스를 따로 작성하는 것이 관리차원에서 더 효율적인 관리가 됩니다. 이 때 의존 객체를 주입하기 위한 이 클래스를 조립기라고 표현합니다.
Assembler.java
public class Assembler {
private MemberDao memberDao;
private MemberRegisterService regSvc;
private ChangePasswordService pwdSvc;
public Assembler() {
memberDao = new MemberDao();
regSvc = new MemberRegisterService(memberDao);
pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
}
public MemberDao getMemberDao() {
return memberDao;
}
public MemberRegisterService getMemberRegisterService() {
return regSvc;
}
public ChangePasswordService getChangePasswordService() {
return pwdSvc;
}
}
main 메서드에서 DI를 구현하지 않고 이렇게 DI를 구현하기 위한 클래스를 하나 따로 만듭니다. 이제 이 조립기의 생성자에서 의존을 주입하면 더 우아한 코드가 됩니다. 그리고 get 메서드를 이용해서 사용할 객체를 꺼내서 사용하면 됩니다. 그리고 DI 예제때와 같이 MemberDao클래스를 상속한 캐쉬를 이용한 클래스 객체로 바꿔줘야 한다면 생성자의 new MemberDao() 대신 new CachedMemberDao()가 들어가게만 수정해주면 됩니다!
활용 예제
public class MainForAssembler {
public static void main(String[] args) throws IOException {
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.println("명령어를 입력하세요:");
String command = reader.readLine();
if (command.equalsIgnoreCase("exit")) {
System.out.println("종료합니다.");
break;
}
if (command.startsWith("new ")) {
processNewCommand(command.split(" "));
continue;
} else if (command.startsWith("change ")) {
processChangeCommand(command.split(" "));
continue;
}
printHelp();
}
}
Assembler클래스를 활용하기 위한 예제이다. new 를 입력하면 새로운 회원 데이터를 추가하고 change 를 입력하면 회원 데이터를 수정한다. 이 때 "new"가 아니라 "new "를 입력한 이유는 공백을 구분자로 이용해서 문자열과 구분하기 위해서와 문자열을 배열로 만들기 위해서 이다.
private static Assembler assembler = new Assembler();
private static void processNewCommand(String[] arg) {
if (arg.length != 5) {
printHelp();
return;
}
MemberRegisterService regSvc = assembler.getMemberRegisterService();
RegisterRequest req = new RegisterRequest();
req.setEmail(arg[1]);
req.setName(arg[2]);
req.setPassword(arg[3]);
req.setConfirmPassword(arg[4]);
if (!req.isPasswordEqualToConfirmPassword()) {
System.out.println("암호와 확인이 일치하지 않습니다.\n");
return;
}
try {
regSvc.regist(req);
System.out.println("등록했습니다.\n");
} catch (DuplicateMemberException e) {
System.out.println("이미 존재하는 이메일입니다.\n");
}
}
private static void processChangeCommand(String[] arg) {
if (arg.length != 4) {
printHelp();
return;
}
ChangePasswordService changePwdSvc =
assembler.getChangePasswordService();
try {
changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
System.out.println("암호를 변경했습니다.\n");
} catch (MemberNotFoundException e) {
System.out.println("존재하지 않는 이메일입니다.\n");
} catch (WrongIdPasswordException e) {
System.out.println("이메일과 암호가 일치하지 않습니다.\n");
}
}
private static void printHelp() {
System.out.println();
System.out.println("잘못된 명령입니다. 아래 명령어 사용법을 확인하세요.");
System.out.println("명령어 사용법:");
System.out.println("new 이메일 이름 암호 암호확인");
System.out.println("change 이메일 현재비번 변경비번");
System.out.println();
}
}
그리고 main()메서드 후에 위의 코드를 추가했다. Assembler 객체를 생성해서 필요한 메서드를 가진 객체를 꺼내서 사용하고 있다. 위에서 Assembler 클래스는 MemberRegisterService 객체를 생성할 때 MemberDao 객체를 주입했다. 그리고MemberDao는 회원 정보를 Map에 담는다. 이로 인해 processNewCommand()메서드가 실행되면 MemberDao 객체의 Map 타입 필드인 map에 회원 데이터가 추가된다. 즉 memberDao와 이 객체를 사용하는 다른 클래스들과 연결(조립)하기 위해 사용하는 클래스가 조립기(Assembler) 클래스다. printHelp()메서드는 중요한 내용은 아니니 유심히 보지 않아도 된다.
마무리
해당 프로그램은 메모리에 회원 데이터를 보관하므로 프로그램을 종료하면 저장한 모든 회원 데이터가 사라진다. 이를 해결하려면 데이터베이스를 이용해야 한다. 다음엔 데이터베이스를 이용해서 다음엔 CRUD를 구현해보겠다. 스프링은 DI를 지원하는 조립기이다. 차이점은 Assembler클래스는 특정 타입의 클래스만 생성하는 반면 스프링은 범용으로 적용할 수 있는 조립기라는 점이다. 다음은 스프링을 이용해 객체를 조립(객체를 생성하고 의존을 주입)하는지 살펴 볼 것이다!
'Server > Spring' 카테고리의 다른 글
Spring - 트랜잭션 처리 (0) | 2020.09.29 |
---|---|
Spring - 로그백(Logback) (0) | 2020.09.29 |
Spring - DataSource와 ConnectionPool이란? (+ HikariCP) (0) | 2020.09.23 |
Spring - AOP 프로그래밍 (관점 지향) [+ Proxy 패턴] (0) | 2020.09.18 |
Spring - 빈 라이프사이클과 범위 (0) | 2020.09.13 |