포스트

Day19 실습프로젝트(Static필드, High Cohesion)

1. 데이터 식별 번호 부여하기

1.1 데이터식별

  • 회원, 프로젝트, 게시글에 대한 고유 번호 생성
  • 배열 중간에 인스턴스를 삭제하여도 고유번호 유지
  • static feild활용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Counter  {
    static int count = 0;
    Counter() {
        this.count++;
        System.out.println(this.count);
    }
}

public class Sample {
    public static void main(String[] args) {
        Counter c1 = new Counter();
        Counter c2 = new Counter();
    }
}
  • 스태틱 필드는 클래스의 고유 필드로 적용
    • 따라서 인스턴스 메서드로 선언하는 것이 아닌 클래스 필드를 생성
    • 전역변수와 같은 역할을 하게 된다.

1.2 데이터 클래스에 seqNo 적용

  • 데이터 클래스에 시퀀스넘버를 생성
  • 시퀀스넘버를 접근하는 getter 메서드 생성
  • 인스턴스 필드에 스태틱필드값 (시퀀스넘버)를 전달할 메서드 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Object{
    //static 필드생성
    private static int seqNo;
	//인스턴스 필드생성
	private int no;
    
    //seqNo getter메서드
    public int getSeqNo(){
    	return ++seqNo;
    }
    
    //no getter 및 setter 메서드
    public setNo(int no){
    	this.no = no;
    }
    
    public getNo(){
    	return no;
    }
}
  • User class

    package bitcamp.myapp2.vo;

    public class User { private static int seqNo; private int no;

    //기타 인스턴스 필드 생량//
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    public static int getSeqNo() {
      return ++seqNo;
    }
    
    public int getNo() {
      return no;
    }
    
    public void setNo(int no) {
      this.no = no;
    }
      	//getter setter 생략//
    }   }
    
  • Board class. Project class 도 동일하다
  • Board class

    package bitcamp.myapp2.vo;

    public class User { private static int seqNo; private int no;

    //기타 인스턴스 필드 생량//
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    public static int getSeqNo() {
      return ++seqNo;
    }
    
    public int getNo() {
      return no;
    }
    
    public void setNo(int no) {
      this.no = no;
    }
      	//getter setter 생략//
    }   }
    
  • Project class

    package bitcamp.myapp2.vo;

    public class User { private static int seqNo; private int no;

    //기타 인스턴스 필드 생량//
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    public static int getSeqNo() {
      return ++seqNo;
    }
    
    public int getNo() {
      return no;
    }
    
    public void setNo(int no) {
      this.no = no;
    }
      	//getter setter 생략//
    }   }
    

1.2 Command 클래스 파일 수정

  • addUser()메서드에 setNo()메서드 추가
  • listUser()메서드에 for문 출력문에 getNo()메서드 추가
  • findByNo()메서드에 userNo탐색 방법 변경
  • 유효성검증 방식 변경(viewUser, updateUser, deleteUser)
  • 인덱스 리턴 메서드 추가
  • deleteUser() for 문 시작인덱스 변경
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  private static void addUser() {
    User user = new User();
    user.setNo(User.getSeqNo());
	//이하 동일//
  }
  
private static void listUser() {
    System.out.println("번호 이름 이메일");
    for (int i = 0; i < userLength; i++) {
      User user = users[i];
      // (i+1) -> user.getNo()로 변경
      System.out.printf("%d %s %s\n", user.getNo(), user.getName(), user.getEmail());
    }
  }
  
  public static User findByNo(int userNo) {
	// if (범위) 탐색 -> for 문 탐색
    for (int i = 0; i < userLength; i++) {
      User user = users[i];
      if (user.getNo() == userNo) {
        return user;
      }
    }
    return null;
  }

//인덱스 리턴 메서드 추가
private static void viewUser() {
    int userNo = Prompt.inputInt("회원번호?");
    //유효성 검증 -> for문 탐색으로 user인스턴스 리턴
    User user = findByNo(userNo);
    if (user == null) {
      System.out.println("없는 회원입니다.");
      return;
    }
    //이하 동일//
  }
  
public static int indexOf(User user){
    for (int i = 0; i < userLength; i++){
      if(users[i] == user){
        return i;
      }
    }
    return -1;
  }
  
private static void deleteUser() {
    int userNo = Prompt.inputInt("회원번호?");
    User user = findByNo(userNo);
    if (user == null) {
      System.out.println("없는 회원입니다.");
      return;
    }
    //해당 인덱스 리턴 메서드
    int index = indexOf(user);
    //userNo가 아닌 index+1로 시작
    for (int i = index + 1; i < userLength; i++) {
      users[i - 1] = users[i];
    }
    users[--userLength] = null;
    System.out.println("삭제했습니다.");
  }
  • 다른 command 클래스도 동일하게 적용
  1. High Cohesion 패턴 적용

2.1 GRASP 방법론

  • GRASP(General Responsibility Assignment SofeWare Patters)

  • 객체지향 설계에서 객체에게 책임을 할당하는 방법론

    1. Information Expert (정보 전문가): 특정 작업을 수행하는 데 필요한 정보를 가지고 있는 객체에게 그 작업을 할당

    2. Creator (생성자): 객체를 생성할 책임을 특정 객체에게 부여하고 생성자는 생성될 객체와 밀접한 관계가 있는 객체로 설정

    3. Controller (컨트롤러): 시스템 이벤트를 처리할 책임을 가지며, 시스템의 주요 제어 흐름을 담당

    4. Low Coupling (낮은 결합도): 객체 간의 의존성을 최소화

    5. High Cohesion (높은 응집도): 객체가 담당하는 책임을 관련된 것들로 모아 하나의 주제로 결집

    6. Polymorphism (다형성): 다형성을 사용하여 동일한 인터페이스를 통해 다양한 객체를 처리

    7. Pure Fabrication (순수 가공): 설계 문제를 해결하기 위해 실제 도메인 모델에는 없는 추가적인 클래스를 만들어 사용

    8. Indirection (간접화): 두 개체 간의 직접적인 연결을 피하고, 간접적인 연결을 통해 결합도를 낮춤

    9. Protected Variations (변화 보호): 변화 가능성이 있는 부분을 캡슐화하여 외부의 영향을 최소화

2.2 High Cohesion(높은 응집도)

  • 기존 command class의 구조 : 서브메뉴들의 흐름제어 + 데이터보관처리
  • 하나의 객체가 2가지의 역할을 담당하고 있으므로 클래스 분리가 필요하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ProjectCommand {
  //데이터보관 필드
  private static final int MAX_SIZE = 10;
  private static final Project[] projects = new Project[MAX_SIZE];
  private static int projectLength = 0;
  
  //UI처리 메서드
  public static void excuteProjectCommand(String command){}
  private static void addProject() {}
  private static void listProject() {}
  private static void viewProject() {}
  private static void updateProject() {}
  private static void deleteProject() {}
  private static void addMembers(Project project) {}
  private static void deleteMembers(Project project) {}
  
  //데이터처리 메서드 
  private static Project findByNo(int projectNo) {}
  private static int indexOf(Project project) {}
}
  • 위 클래스를 2개의 클래스로 분리
    • 데이터보관 및 처리 메서드 // UI처리 메소드
    • 이를 통해 로직의 복잡성을 낮추고 유지 보수를 용이하게 한다.

    public class ProjectList { //데이터보관 필드 private static final int MAX_SIZE = 10; private static final Project[] projects = new Project[MAX_SIZE]; private static int projectLength = 0;

    1
    2
    3
    
    //데이터처리 메서드 
    private static Project findByNo(int projectNo) {}
    private static int indexOf(Project project) {}   }
    

    public class ProjectCommand { //UI처리 메서드 public static void excuteProjectCommand(String command){} private static void addProject() {} private static void listProject() {} private static void viewProject() {} private static void updateProject() {} private static void deleteProject() {} private static void addMembers(Project project) {} private static void deleteMembers(Project project) {}

    }

2.3 클래스 분리하기

  • UserList 클래스 생성
    • 유저정보를 저장하는 클래스 필드 생성
    • 유저정보들을 저장하는 유저배열 생성 메서드
    • 유효한 유저정보를 삭제하는 메서드
    • 유효한 유저수만큼 배열 조정하는 메서드
    • 유효한 유저 정보를 반환하는 메서드
    • 유저 정보 인덱스를 반환하는 메서드

    package bitcamp.myapp2.command;

    import bitcamp.myapp2.vo.User;

    public class UserList { private static final int MAX_SIZE = 10; private static final User[] users = new User[MAX_SIZE]; private static int userLength = 0;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    
    public static void add(User user) {
      users[userLength++] = user;
    }
    
    public static User delete(int userNo) {
      User deleteUser = findByNo(userNo);
      if (deleteUser == null) {
        return null;
      }
      int index = indexOf(deleteUser);
      for (int i = index + 1; i < userLength; i++) {
        users[i - 1] = users[i];
      }
      users[--userLength] = null;
      return deleteUser;
    }
    
    public static User[] toArray() {
      User[] arr = new User[userLength];
      for (int i = 0; i < arr.length; i++) {
        arr[i] = users[i];
      }
      return arr;
    }
    
    public static User findByNo(int userNo) {
      for (int i = 0; i < userLength; i++) {
        User user = users[i];
        if (user.getNo() == userNo) {
          return user;
        }
      }
      return null;
    }
    
    public static int indexOf(User user) {
      for (int i = 0; i < userLength; i++) {
        if (users[i] == user) {
          return i;
        }
      }
      return -1;
    }   }
    
  • UserCommand 클래스 수정
    • 기존 Command 메서드 중 명령 관련 메소드로 구성
    • addUser()메서드 추가
    • viewUser() for문 호출 방식 변경
    • deleteUser() 메서드 변경

    package bitcamp.myapp.command;

    import bitcamp.myapp.util.Prompt; import bitcamp.myapp.vo.User;

    public class UserCommand {

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    
    public static void executeUserCommand(String command) {
      System.out.printf("[%s]\n", command);
      switch (command) {
        case "등록":
          addUser();
          break;
        case "조회":
          viewUser();
          break;
        case "목록":
          listUser();
          break;
        case "변경":
          updateUser();
          break;
        case "삭제":
          deleteUser();
          break;
      }
    }
    
    private static void addUser() {
      User user = new User();
      user.setName(Prompt.input("이름?"));
      user.setEmail(Prompt.input("이메일?"));
      user.setPassword(Prompt.input("암호?"));
      user.setTel(Prompt.input("연락처?"));
      user.setNo(User.getNextSeqNo());
      UserList.add(user);
    }
    
    private static void listUser() {
      System.out.println("번호 이름 이메일");
      for (User user : UserList.toArray()) {
        System.out.printf("%d %s %s\n", user.getNo(), user.getName(), user.getEmail());
      }
    }
    
    private static void viewUser() {
      int userNo = Prompt.inputInt("회원번호?");
      User user = UserList.findByNo(userNo);
      if (user == null) {
        System.out.println("없는 회원입니다.");
        return;
      }
    
      System.out.printf("이름: %s\n", user.getName());
      System.out.printf("이메일: %s\n", user.getEmail());
      System.out.printf("연락처: %s\n", user.getTel());
    }
    
    private static void updateUser() {
      int userNo = Prompt.inputInt("회원번호?");
      User user = UserList.findByNo(userNo);
      if (user == null) {
        System.out.println("없는 회원입니다.");
        return;
      }
    
      user.setName(Prompt.input("이름(%s)?", user.getName()));
      user.setEmail(Prompt.input("이메일(%s)?", user.getEmail()));
      user.setPassword(Prompt.input("암호?"));
      user.setTel(Prompt.input("연락처(%s)?", user.getTel()));
      System.out.println("변경 했습니다.");
    }
    
    private static void deleteUser() {
      int userNo = Prompt.inputInt("회원번호?");
      User deletedUser = UserList.delete(userNo);
      if (deletedUser != null) {
        System.out.printf("'%s' 회원을 삭제 했습니다.\n", deletedUser.getName());
      } else {
        System.out.println("없는 회원입니다.");
      }
    }
    

    }

  • 다른 클래스 파일도 동일하게 적용
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.