코드 리팩토링(2)

승환·2025년 1월 22일

📌 코드 리뷰

지난 포스트에서 아이디어를 잘 작성했는데, 코드를 작성하는데 있어서 문제가 없진 않았다.
해결책과 동시에 코드를 첨부한다.


📌 코드

 public void makeTreeNode() {
        while (!priorityQueue.isEmpty()) {
            CategoryTest categoryTest = priorityQueue.poll();
            if (categoryTest.getDepth() == 0) { // Root node
                TreeNode<String, CategoryTest> root = new TreeNode<>(categoryTest.getSeq().toString(), categoryTest.getName(), categoryTest);
                unionAll(root);
                categoryTree = new Tree<>(root);
                break;
            }
            if (contains(categoryTest.getSeq().toString())) {
                unionTreeNode(categoryTest);
            } else {
                insertOrAddToMap(categoryTest);
            }
        }
    }

메인 코드는 이렇게 동작한다 하나하나씩 살펴보면

while (!priorityQueue.isEmpty()) {
CategoryTest categoryTest = priorityQueue.poll();

큐에서 모든 자료를 다 꺼낼 때 까지 반복하도록 한다.

if (categoryTest.getDepth() == 0) { // Root node
                TreeNode<String, CategoryTest> root = new TreeNode<>(categoryTest.getSeq().toString(), categoryTest.getName(), categoryTest);
                unionAll(root);
                categoryTree = new Tree<>(root);
                break;
            }

depth를 검사했을 때 0이라면 최상위 노드이기 때문에 root노드를 만들어서 최상위 노드를 만들어준다.

public void unionAll(TreeNode<String, CategoryTest> root) {
        LinkedList<TreeNode<String, CategoryTest>> unionList = map.get(root.getKey());
        root.setChildren(unionList);
    }

사용되는 unionAll함수이다. 트리를 만들다 보면 루트 트리 아래에 도달하면(depth가 1) map안에는
depth가 1인 것 하나만 남아있어야 한다. 그 부분을 구현한 것이다.
setChildren을 통해 리스트를 루트에 연결해준다.

 if (contains(categoryTest.getSeq().toString())) {
                unionTreeNode(categoryTest);

seq가 이미 map에 키로 포함되어있는 경우이다. 이 경우에는 map에서 리스트를 해당 노드의 자식으로 만들어 줘야 한다.

    public void unionTreeNode(CategoryTest categoryTest) {
        TreeNode<String, CategoryTest> node = new TreeNode<>(categoryTest.getSeq().toString(), categoryTest.getName(), categoryTest);
        List<TreeNode<String, CategoryTest>> children = map.get(categoryTest.getSeq().toString());

        if (children != null) {
            node.setChildren(new LinkedList<>(children)); // Copy and set children
        }
        map.computeIfAbsent(categoryTest.getParentSeq().toString(), k -> new LinkedList<>()).add(node);
        map.remove(categoryTest.getSeq().toString()); // Safely remove child data after moving
    }

그 부분을 구현하는 unionTreeNode이다. 해당 노드의 seq값은 자식 노드 그니까 map에 들어간 노드의 parnetSeq값일 것이다. 그것을 이용해서 자식을 찾는다. 이후에 자식이 비어있지 않다면 자식을 부모 노드로 연결을 해주는데, 이때 새로운 리스트로연결을 해줘야 한다.
이유는 참조에 관련된 이야기인데, 아래 코드를 보면
remove를 통해 원래 있었던 자식의 공간을 지우고 있다. 이 과정에서 깊은 복사가 이뤄지지 않으면
복사했던 객체의 참조도 지워지게 되서 자식이 지워지는 경우가 발생한다. 그래서 새로운 객체로 옮겨서
주소를 옮겨주는 것이다.
이 모든 경우에도 포함되지 않는다면,

    public void InsertOrAddToMap(CategoryTest categoryTest) {
        TreeNode<String, CategoryTest> node = new TreeNode<>(categoryTest.getSeq().toString(), categoryTest.getName(), categoryTest);
        map.computeIfAbsent(categoryTest.getParentSeq().toString(), k -> new LinkedList<>()).add(node);
    }

이미 키가 있다면 추가하고 없다면 새로 만들어서 추가하는 메서드이다. computeIfAbsent 메서드는 Map에서 제공하는 메서드인데, categoryTest.getParentSeq().toString() 를 찾는 것에 실패한다면 새로운 링크리스트를 만들어서 add하고 성공한다면 getParentSeq를 한 곳에 add하는 메서드이다. 참이면 본인을 반환하고 거짓이라면 뒤를 반환한다.

    public Tree<String, DepartmentTest> getTree() {
        makeTreeNode();
        return Tree;
    }

만든 트리를 반환하는 로직이다. 생성자에 makeTreeNode를 넣을수도 있지만 LazyEvaluation을 하기 위해서 getTree에 넣어서 원할때만 트리를 만들도록 하였다.


정리

코드를 짜는 것은 어렵지 않았다. 몇 가지 이슈가 있었지만 코드 내용 자체는 간단했고, 트리를 만드는 것에 한하여 속도 향상 또한 많이 좋아졌다.
이제 이걸 다양한 곳에 사용하기 위한 제네릭 클래스를 만들어볼 것이다.

profile
왕초보 학부생

0개의 댓글