클래스는 하나의 책임, 하나의 변경 사유만 가져야 한다.
아래의 장점들이 모여서 테스트 & 검증이 쉬워지며, 유지보수 난이도도 감소함
-가독성 증가 : 클래스 하나의 행동 범위가 작아지므로 읽고 이해하기 쉬워짐
-결합도 감소 : 하나의 클래스 변경이 다른 코드에 미치는 영향을 줄일 수 있다.
-재사용성 증가 : 코드의 목적성이 명확하여 비슷한 케이스에 쉽게 다시 적용 가능
확장에 열려있고, 변경에는 닫혀있어야 한다.
기능을 확장하는 과정에서 수정을 최소화하여야 한다.
-설계 단계에서 변경이 일어나도 되는 부분과, 변경하면 안 될 부분을 구분하여 설계한다.
-인터페이스, 다형성 등을 통해 구현한다.
메세지를 만들려면
1. 메세지를 보낼 채널이 존재하는가?
2. 메세지를 작성한 유저가 해당 채널에 속한 멤버인가?
2가지를 검사해야 한다.
해당 검사는 메시지 자체의 생성 여부가 아니라, 특정 채널에 메시지를 추가할 수 있는지에 대한 검증이므로 채널의 책임으로 분리했다.
만약 추가할 수 없는 메세지일 경우 채널측에서 예외를 throw해주기 때문에 메세지의 JCF에 빈 메세지가 들어가는 일도 막을 수 있다.
public class JCFMessageService implements MessageService {
public void create(UUID channelId, UUID userId, String message) {
Message messageCreate = new Message(userId, message);
// 채널서비스 측에서
JCFChannelService.getInstance()
.addMessage(channelId, userId, messageCreate.getId());
messageMap.put(messageCreate.getId(), messageCreate);
reactionMap.put(messageCreate.getId(), new HashMap<>());
}
}
public void addMessage(UUID channelId, UUID userId, UUID messageId) {
if (!userRoleMap.containsKey(channelId)) {
throw new IllegalArgumentException("채널 id가 없습니다.");
}
if (!userRoleMap.get(channelId).containsKey(userId)) {
throw new IllegalArgumentException(
"유저 id가 없거나 유저가 채널 소속이 아닙니다."
);
}
messagesListMap.get(channelId).add(messageId);
}
유저 생성에 대한 책임
1.유저를 등록할 때 Email이 Email형식인가? 는 입력 방식과 상관없이 항상 진행해야 할 검사이다.(도메인 레벨의 책임)
2.열거형 변수 NitroLevel은 print와 scanner를 중심으로 하는 현재 실습 방식에선 검사해야 하지만 콤보박스, 라디오버튼 같은 방식으로 입력받으면 검사할 필요가 없다.(입력 방식의 책임)
그래서 1은 User 엔티티에서 검사하지만 2는 현재 실습에서 scanner입력에 대해 관리해주는 Manager클래스에서 검사했다.
코드 public User(String email, String password, String name, NitroLevel nitroLevel) {
super();
if (!email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) {
throw new IllegalArgumentException("메일 형식이 아님.");
}
this.email=email;
this.password=password;
this.name=name;
this.nitroLevel=nitroLevel;
}
//Manager에서 열거형에 대한 scanner 입력을 검사하는 부분
System.out.println("니트로 레벨은 아래 목록이 있습니다.");
for(NitroLevel level : NitroLevel.values()){
System.out.println(level);
}
//////////////////////////
while (true) {
System.out.println("니트로 레벨을 입력하세요.");
nitro = sc.next();
try {
nitroLevel = NitroLevel.valueOf(nitro);
break;
} catch (IllegalArgumentException e) {
System.out.println("잘못된 니트로 레벨입니다. 다시 입력해주세요.");
}
}
현재 실습에서 JCFUserService를 만들기 전에 UserService에서 필수적인 메서드들을 정의하는 식으로 진행하고 있다. 이후 File형식으로 기능을 확장할 때 UserService를 불러와 쉽게 틀을 잡을 수 있을 것이다.